home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 21 / Cream of the Crop 21 (Terry Blount) (October 1996).iso / program / freeli22.zip / 386LIB1.ASX < prev    next >
Text File  |  1996-09-01  |  95KB  |  3,212 lines

  1. ~~~C_START
  2. Ideal
  3.  
  4. Extrn       main:near
  5. Public      startup, exit
  6. Public      TopByte, AtExitCnt
  7.  
  8. Model Tiny
  9. CodeSeg
  10. P386
  11.  
  12. ;****************** startup() -- Start program
  13.  
  14. Proc        startup
  15.  
  16.             pushf                   ;Check for 386+
  17.             pushf
  18.             pop ax
  19.             xor ax,7000h
  20.             push ax
  21.             popf
  22.             pushf
  23.             pop bx
  24.             popf
  25.             cmp ax,bx
  26.             je p0_badcpu
  27.  
  28.             mov ax,3001h            ;Check for DOS 4.0
  29.             int 21h
  30.             cmp al,4
  31.             jb p0_baddos
  32.  
  33.             mov ah,4Ah              ;Modify memory allocation
  34.             mov bx,1000h            ;Keep first 64K
  35.             int 21h                 ;DOS call
  36.  
  37.             mov sp,0FF00h           ;Shift stack down 256 bytes
  38.  
  39.             mov ax,2523h            ;Set null Ctrl-C handler
  40.             mov dx,offset IntRet    ;so that Ctrl-C can't
  41.             int 21h                 ;abort the program
  42.  
  43.             mov ax,3500h            ;Get current Int 0 handler
  44.             int 21h                 ; (divide by zero)
  45.  
  46.             mov [word OldInt0],bx   ;Save handler
  47.             mov [word OldInt0+2],es
  48.  
  49.             push cs                 ;Restore ES
  50.             pop es
  51.  
  52.             mov ax,2500h            ;Set the divide by zero
  53.             mov dx,offset DivZero   ;handler: now it just
  54.             int 21h                 ;ignores the error
  55.  
  56.             mov ax,0FB00h           ;Initialize dynamic memory
  57.             sub ax,offset TopByte   ;leaving 768 bytes for the
  58.             mov [word TopByte],ax   ;stack (which is at 0FF00h)
  59.             mov [byte TopByte+2],2  ;Initial block is free, last
  60.  
  61.             mov di,sp               ;Parse arguments
  62.             call ParseArgs
  63.  
  64.             call main               ;Call main function
  65.  
  66.             push ax                 ;Terminate with return code
  67.             call exit
  68.  
  69. p0_baddos:  push offset BadDosStr   ;'Bad Dos' message
  70.             jmp p0_error
  71.  
  72. p0_badcpu:  push offset BadCPUStr   ;'Bad CPU' message
  73.  
  74. p0_error:   mov dx,offset BadStr    ;Print first part
  75.             mov ah,9
  76.             int 21h
  77.             pop dx                  ;Print second part
  78.             int 21h
  79.             mov ax,4CFFh            ;Return with error 255
  80.             int 21h
  81.  
  82. EndP        startup
  83.  
  84. ;****************** DivZero -- Divide by zero handler
  85.  
  86. Proc        DivZero
  87.  
  88.             push bp                 ;Set up stack frame
  89.             mov bp,sp
  90.             pusha                   ;Save all registers
  91.             push ds
  92.  
  93.             xor cx,cx               ;CX = displacement
  94.  
  95.             mov ds,[bp+4]           ;DS:BX = DIV instruction
  96.             mov bx,[bp+2]
  97.             cmp [byte bx],66h       ;Skip past opsize, if any
  98.             jne $+4
  99.             inc bx
  100.             inc cx
  101.             mov al,[bx+1]           ;AL = AH = ModRM byte
  102.             mov ah,al
  103.  
  104.             and al,0C0h             ;Mask off mode bits
  105.             cmp al,0C0h             ;Mode = 11 (no disp)?
  106.             je DZ_dis0
  107.             cmp al,040h             ;Mode = 01 (1 byte disp)?
  108.             je DZ_dis1
  109.             cmp al,080h             ;Mode = 10 (2 byte disp)?
  110.             je DZ_dis2
  111.             cmp ah,36h              ;Mode = 00.  No disp except
  112.             jne DZ_dis0             ;if R/M = 110 (2 byte disp).
  113.  
  114. DZ_dis2:    inc cx                  ;2 byte displacement
  115. DZ_dis1:    inc cx                  ;1 byte displacement
  116. DZ_dis0:    inc cx                  ;Instruction is two bytes
  117.             inc cx
  118.             add [bp+2],cx           ;Skip past instruction
  119.  
  120. DZ_done:    pop ds                  ;Restore registers
  121.             popa
  122.             pop bp                  ;Delete stack frame
  123. IntRet:     iret                    ;Interrupt return
  124.  
  125. EndP        DivZero
  126.  
  127. ;****************** Internal data
  128.  
  129. OldInt0:                            ;Old divide-by-zero handler
  130. BadStr      db 'Need at least $'    ;OK to overwrite strings
  131. BadCPUStr   db 'an 80386 CPU',13,10,'$'
  132. BadDosStr   db 'DOS 4.0',13,10,'$'
  133.  
  134. AtExitCnt   dw 0                    ;Exit function count
  135. AtExitTblO  equ 0FF60h              ;Exit function table offset
  136.  
  137. ;****************** exit() -- Terminate program
  138. ;void exit(int retval);
  139.  
  140. Proc        exit
  141.  
  142.             mov ax,2500h            ;Reset the default divide
  143.             mov dx,[word OldInt0]   ;by zero handler
  144.             mov ds,[word OldInt0+2]
  145.             int 21h
  146.  
  147.             push cs                 ;Restore DS
  148.             pop ds
  149.  
  150.             mov cx,[AtExitCnt]      ;CX = atexit count
  151.             jcxz p1_done            ;No exit functions?
  152.             mov si,AtExitTblO       ;SI = atexit table
  153.  
  154. p1_loop:    lodsw                   ;Get function
  155.             call ax                 ;Call function
  156.             loop p1_loop            ;Loop back
  157.  
  158. p1_done:    pop ax ax               ;Pop arg into AX
  159.             mov ah,4Ch              ;Terminate program
  160.             int 21h                 ;DOS call
  161.  
  162. EndP        exit
  163.  
  164. ;**************************** ParseArgs() -- internal: Parse arguments
  165.  
  166. Proc        ParseArgs
  167.             ;Supply DI = 256-byte buffer, CS = DS = ES
  168.             ;Returns CX = number of arguments
  169.             ;the buffer will contain a list of
  170.             ;near offsets to AsciiZ strings
  171.             ;(and the strings themselves)
  172.  
  173.             pusha                   ;Save all registers
  174.  
  175.             mov bx,di               ;BX = buffer
  176.             mov cl,[80h]            ;CX = length of command line
  177.             xor ch,ch               ;which is stored at 80h
  178.  
  179.             push cx                 ;Save CX
  180.             mov si,81h              ;SI = command line
  181.             add di,80h              ;DI = second half of buffer
  182.             push di                 ;Save DI
  183.             rep movsb               ;Move command line out of DTA
  184.             xor al,al               ;Replace the CR at the end
  185.             stosb                   ;with a null
  186.             pop di cx               ;Restore DI, length in CX
  187.             inc cx                  ;Make length include last null
  188.             xor dx,dx               ;Zero argument counter
  189.             mov al,' '              ;AL = space
  190.  
  191. p2_loop:    repe scasb              ;Search for a non-space
  192.             dec di
  193.             inc cx
  194.             cmp [byte di],0         ;Is it a null?
  195.             je p2_done
  196.             mov [bx],di             ;Store offset in list
  197.             inc bx                  ;Advance pointers
  198.             inc bx
  199.             inc dx
  200.             repne scasb             ;Search for a space
  201.             mov [byte di-1],0       ;Replace it by a null
  202.             jmp p2_loop             ;Loop back
  203.  
  204. p2_done:    mov bp,sp               ;Change pushed AX
  205.             mov [bp+12],dx
  206.             popa                    ;Restore registers
  207.             ret                     ;Return
  208.  
  209. EndP        ParseArgs
  210.  
  211. UDataSeg                            ;Uninit. data seg: dummy
  212.  
  213. Label       TopByte                 ;Top byte of code (start of heap)
  214.  
  215. End
  216.  
  217. ~~~C_ATEXIT
  218. Ideal
  219.  
  220. Extrn       AtExitCnt:word
  221. Public      atexit
  222.  
  223. Model Tiny
  224. CodeSeg
  225. P386
  226.  
  227. AtExitTblO  equ 0FF60h              ;Exit function table offset
  228.  
  229. ;****************** atexit() -- Add exit function
  230. ;int atexit(void *func);
  231.  
  232. func        equ bp+4
  233.  
  234. Proc        atexit
  235.  
  236.             push bp                 ;Set up stack frame
  237.             mov bp,sp
  238.             push bx                 ;Save BX
  239.  
  240.             cmp [word AtExitCnt],16 ;16 functions max
  241.             jae p2_error
  242.  
  243.             mov bx,[AtExitCnt]      ;BX = offset
  244.             add bx,bx
  245.             mov ax,[func]           ;AX = function
  246.             mov [AtExitTblO+bx],ax  ;Add function to table
  247.             inc [word AtExitCnt]    ;Increment count
  248.  
  249. p2_done:    pop bx                  ;Restore BX
  250.             pop bp                  ;Delete stack frame
  251.             ret 2                   ;Return
  252.  
  253. p2_error:   xor ax,ax               ;Return 0: failure
  254.             jmp p2_done
  255.  
  256. EndP        atexit
  257.  
  258. End
  259.  
  260. ~~~C_PUTCHR
  261. Ideal
  262.  
  263. Public      PUT_CHAR
  264.  
  265. Model Tiny
  266. CodeSeg
  267. P386
  268.  
  269. ;****************** PUT_CHAR -- Like Int 29h but with redirection.
  270. ;                               Takes AL = char.
  271.  
  272. Proc        PUT_CHAR
  273.  
  274.             pusha                   ;Save registers
  275.             xchg dx,ax              ;STDOUT output, DL = char
  276.             mov ah,2
  277.             int 21h                 ;DOS call
  278.             popa                    ;Restore registers
  279.             ret                     ;Return
  280.  
  281. EndP        PUT_CHAR
  282.  
  283. End
  284.  
  285. ~~~C_FILES
  286. Ideal
  287.  
  288. Public      fopen,fclose,fsetbuf
  289.  
  290. Model Tiny
  291. CodeSeg
  292. P386
  293.  
  294. ;****************** File Structure . . .
  295.  
  296. ;                   Offset  Size    Description
  297.  
  298. ;                     0     Word    File handle
  299. ;                     2     Word    File mode
  300. ;                     4     Dword   Buffer position in file
  301. ;                     8     Word    Buffer pointer position
  302. ;                     10    Word    Number of bytes in buffer
  303. ;                     12    Word    Size of buffer (N)
  304. ;                     14    Word    Signature 'FI'
  305. ;                     16    N bytes File buffer
  306.  
  307. BUF_SIZ     dw 1024                 ;Buffer size (default 1K)
  308.  
  309. F_MODES     db 00h,01h              ;0 = open for read
  310.             db 02h,11h              ;1 = open/create for read/write
  311.             db 02h,01h              ;2 = open for read/write
  312.             db 02h,12h              ;3 = create/truncate for read/write
  313.             db 02h,10h              ;4 = create for read/write
  314.             db 6 dup(0)             ;Fail for 5, 6, 7
  315.  
  316. ;****************** fopen() -- Open a buffered file
  317. ;int fopen(char *fname, int mode);
  318.  
  319. fname       = bp+6
  320. mode        = bp+4
  321.  
  322. Proc        fopen
  323.  
  324.             push bp                 ;Set up stack frame
  325.             mov bp,sp
  326.             push ds si bx cx dx     ;Save registers
  327.  
  328.             mov bx,[mode]           ;BX = mode
  329.             and bx,7                ;Mode mod 8
  330.             add bx,bx
  331.             movzx dx,[F_MODES+bx+1] ;BX:DX = DOS mode
  332.             movzx bx,[F_MODES+bx]
  333.  
  334.             mov ax,6C00h            ;Extended open file
  335.             xor cx,cx               ;Normal attribute
  336.             mov si,[fname]          ;SI = name
  337.             int 21h                 ;DOS call
  338.             jc p1_err1              ;Check for errors
  339.  
  340.             xchg dx,ax              ;DX = handle
  341.  
  342.             mov ah,48h              ;Allocate memory
  343.             mov bx,[BUF_SIZ]        ;BX = num. of paras
  344.             shr bx,4                ; = (BUF_SIZ / 16) + 1
  345.             inc bx
  346.             int 21h                 ;DOS call
  347.             jc p1_err2              ;Check for errors
  348.  
  349.             mov ds,ax               ;DS = segment
  350.             mov [word 0],dx         ;[word 0] = handle
  351.             mov cx,[mode]
  352.             mov [word 2],cx         ;[word 2] = mode
  353.             xor bx,bx
  354.             mov [word 4],bx         ;[dword 4] = buffer position
  355.             mov [word 6],bx
  356.             mov [word 8],bx         ;[word 8] = buffer pointer
  357.             mov bx,[cs:BUF_SIZ]
  358.             mov [word 12],bx        ;[word 12] = buffer size
  359.             mov [word 14],'FI'      ;[word 14] = 'FI': signature
  360.  
  361.             mov bx,dx               ;BX = handle
  362.             mov ah,3Fh              ;Read file
  363.             mov cx,[cs:BUF_SIZ]     ;BUF_SIZ bytes
  364.             mov dx,16               ;Buffer offset
  365.             int 21h                 ;DOS call
  366.  
  367.             mov [word 10],ax        ;Set byte count
  368.  
  369.             mov ax,ds               ;AX = segment
  370.  
  371. p1_done:    pop dx cx bx si ds      ;Restore registers
  372.             pop bp                  ;Delete stack frame
  373.             ret 4                   ;Return
  374.  
  375. p1_err2:    mov ah,3Eh              ;Out of memory, close file
  376.             mov bx,dx               ;BX = handle
  377.             int 21h                 ;DOS call
  378.  
  379. p1_err1:    xor ax,ax               ;Error, return 0
  380.             jmp p1_done
  381.  
  382. EndP        fopen
  383.  
  384. ;****************** fclose() -- Close a buffered file
  385. ;void fclose(int fptr);
  386.  
  387. fptr        = bp+4
  388.  
  389. Proc        fclose
  390.  
  391.             push bp                 ;Set up stack frame
  392.             mov bp,sp
  393.             push ds es              ;Save registers
  394.             pusha
  395.  
  396.             mov ds,[fptr]           ;DS = seg of file
  397.             cmp [word 14],'FI'      ;Check for signature
  398.             jne p2_done
  399.  
  400.             mov bx,[word 0]         ;BX = handle
  401.  
  402.             cmp [byte 2],0          ;Read only, can't write buffer
  403.             je p2_skip
  404.  
  405.             mov ax,4200h            ;Move file ptr
  406.             mov cx,[word 6]         ;CX:DX = buffer pos
  407.             mov dx,[word 4]
  408.             int 21h                 ;DOS call
  409.  
  410.             mov ah,40h              ;Write file
  411.             mov cx,[word 10]        ;CX = bytes
  412.             mov dx,16               ;Buffer offset
  413.             int 21h                 ;DOS call
  414.  
  415. p2_skip:    mov ah,3Eh              ;Close file
  416.             int 21h                 ;DOS call
  417.  
  418.             mov ah,49h              ;Free memory
  419.             push ds                 ;ES = segment
  420.             pop es
  421.             int 21h                 ;DOS call
  422.  
  423. p2_done:    popa                    ;Restore registers
  424.             pop es ds
  425.             pop bp                  ;Delete stack frame
  426.             ret 2                   ;Return
  427.  
  428. EndP        fclose
  429.  
  430. ;****************** fsetbuf() -- Set buffer size (for future use)
  431. ;int fsetbuf(int bsize);
  432.  
  433. bsize       = bp+4
  434.  
  435. Proc        fsetbuf
  436.  
  437.             push bp                 ;Set up stack frame
  438.             mov bp,sp
  439.  
  440.             mov ax,[bsize]          ;AX = size
  441.             and ax,7FF0h            ;Put it in range
  442.             cmp ax,128
  443.             jb $+5
  444.             mov ax,128
  445.             mov [BUF_SIZ],ax        ;Set buffer size
  446.  
  447.             pop bp                  ;Delete stack frame
  448.             ret 2                   ;Return
  449.  
  450. EndP        fsetbuf
  451.  
  452. End
  453.  
  454. ~~~C_FPUTC
  455. Ideal
  456.  
  457. Public      fputc
  458.  
  459. Model Tiny
  460. CodeSeg
  461. P386
  462.  
  463. ;****************** fputc() -- Put char to buffered file
  464. ;int fputc(int fptr, int chr);
  465.  
  466. fptr        = bp+6
  467. chr         = bp+4
  468.  
  469. Proc        fputc
  470.  
  471.             push bp                 ;Set up stack frame
  472.             mov bp,sp
  473.             push ds si bx cx dx     ;Save registers
  474.  
  475.             mov ds,[fptr]           ;DS = seg of file
  476.             cmp [word 14],'FI'      ;Check for signature
  477.             jne p1_error
  478.  
  479.             mov bx,[word 0]         ;BX = handle
  480.  
  481.             cmp [word 2],0          ;Read only, can't put char
  482.             je p1_error
  483.  
  484.             mov si,[word 8]         ;SI = pointer pos
  485.             cmp si,[word 12]        ;Filled buffer?
  486.             jb p1_write             ;Jump if not
  487.  
  488.             mov ax,4200h            ;Move file ptr
  489.             mov cx,[word 6]         ;CX:DX = buffer pos
  490.             mov dx,[word 4]
  491.             int 21h                 ;DOS call
  492.  
  493.             mov ah,40h              ;Write file
  494.             mov cx,[word 12]        ;CX = bytes
  495.             mov dx,16               ;Buffer offset
  496.             int 21h                 ;DOS call
  497.  
  498.             mov ah,3Fh              ;Read file, same data...
  499.             int 21h                 ;DOS call
  500.             mov [word 10],ax        ;Set byte count
  501.  
  502.             xor si,si
  503.             add [word 4],cx         ;Advance buffer position
  504.             adc [word 6],si
  505.             mov [word 8],si         ;Pointer pos = 0
  506.  
  507. p1_write:   mov al,[chr]            ;AX = char
  508.             xor ah,ah
  509.             mov [16+si],al          ;Put char in buffer
  510.             inc si                  ;Advance pointer
  511.             mov [word 8],si
  512.             cmp si,[word 10]        ;Hit last byte?
  513.             jna p1_done
  514.  
  515.             inc [word 10]           ;Advance byte count
  516.  
  517. p1_done:    pop dx cx bx si ds      ;Restore registers
  518.             pop bp                  ;Delete stack frame
  519.             ret 4                   ;Return
  520.  
  521. p1_error:   mov ax,-1               ;Error, return EOF
  522.             jmp p1_done
  523.  
  524. EndP        fputc
  525.  
  526. End
  527.  
  528. ~~~C_FGETC
  529. Ideal
  530.  
  531. Public      fgetc
  532.  
  533. Model Tiny
  534. CodeSeg
  535. P386
  536.  
  537. ;****************** fgetc() -- Get char from buffered file
  538. ;int fgetc(int fptr);
  539.  
  540. fptr        = bp+4
  541.  
  542. Proc        fgetc
  543.  
  544.             push bp                 ;Set up stack frame
  545.             mov bp,sp
  546.             push ds si bx cx dx     ;Save registers
  547.  
  548.             mov ds,[fptr]           ;DS = seg of file
  549.             cmp [word 14],'FI'      ;Check for signature
  550.             jne p1_error
  551.  
  552.             mov bx,[word 0]         ;BX = handle
  553.  
  554.             mov si,[word 8]         ;SI = pointer pos
  555.             mov cx,[word 12]        ;CX = buffer size
  556.             cmp si,cx               ;End of buffer?
  557.             jb p1_read              ;Jump if not
  558.  
  559.             xor si,si
  560.             add [word 4],cx         ;Advance buffer position
  561.             adc [word 6],si
  562.             mov [word 2],si         ;Pointer pos = 0
  563.  
  564.             mov ax,4200h            ;Move file ptr
  565.             mov cx,[word 6]         ;CX:DX = buffer pos
  566.             mov dx,[word 4]
  567.             int 21h                 ;DOS call
  568.  
  569.             mov ah,3Fh              ;Read file
  570.             mov cx,[word 12]        ;CX = bytes
  571.             mov dx,16               ;Buffer offset
  572.             int 21h                 ;DOS call
  573.             mov [word 10],ax        ;Set byte count
  574.  
  575. p1_read:    cmp si,[word 10]        ;Hit last byte?
  576.             jae p1_error
  577.  
  578.             mov al,[16+si]          ;Get char from buffer
  579.             xor ah,ah
  580.             inc si                  ;Advance pointer
  581.             mov [word 8],si
  582.  
  583. p1_done:    pop dx cx bx si ds      ;Restore registers
  584.             pop bp                  ;Delete stack frame
  585.             ret 2                   ;Return
  586.  
  587. p1_error:   mov ax,-1               ;Error, return EOF
  588.             jmp p1_done
  589.  
  590. EndP        fgetc
  591.  
  592. End
  593.  
  594. ~~~C_FSEEK
  595. Ideal
  596.  
  597. Public      fseek,ftell
  598.  
  599. Model Tiny
  600. CodeSeg
  601. P386
  602.  
  603. ;****************** fseek() -- Seek to position in buffered file
  604. ;int fseek(int fptr, long pos, int cmd);
  605.  
  606. fptr        = bp+10
  607. pos         = bp+6
  608. cmd         = bp+4
  609.  
  610. Proc        fseek
  611.  
  612.             push bp                 ;Set up stack frame
  613.             mov bp,sp
  614.             push ds bx cx dx        ;Save registers
  615.  
  616.             mov ds,[fptr]           ;DS = seg of file
  617.             cmp [word 14],'FI'      ;Check for signature
  618.             jne p1_error
  619.  
  620.             mov bx,[word 0]         ;BX = handle
  621.  
  622.             cmp [word 2],0          ;Read only, can't write buffer
  623.             je p1_seek
  624.  
  625.             mov ax,4200h            ;Move file ptr
  626.             mov cx,[word 6]         ;CX:DX = buffer pos
  627.             mov dx,[word 4]
  628.             int 21h                 ;DOS call
  629.  
  630.             mov ah,40h              ;Write file
  631.             mov cx,[word 10]        ;CX = bytes
  632.             mov dx,16               ;Buffer offset
  633.             int 21h                 ;DOS call
  634.  
  635. p1_seek:    mov ax,4200h            ;Move file ptr
  636.             mov cx,[word 6]         ;CX:DX = current pos
  637.             mov dx,[word 4]         ; = buffer pos + pointer
  638.             add dx,[word 8]
  639.             adc cx,0
  640.             int 21h                 ;DOS call
  641.  
  642.             mov ah,42h              ;Move file ptr
  643.             mov al,[cmd]            ;AL = command
  644.             mov cx,[pos+2]          ;CX:DX = new pos
  645.             mov dx,[pos]
  646.             int 21h                 ;DOS call
  647.  
  648.             mov [word 6],dx         ;Save position
  649.             mov [word 4],ax
  650.  
  651.             mov ah,3Fh              ;Read file
  652.             mov cx,[word 12]        ;CX = bytes
  653.             mov dx,16               ;Buffer offset
  654.             int 21h                 ;DOS call
  655.  
  656.             mov [word 10],ax        ;Set byte count
  657.             mov [word 8],0          ;Pointer = 0
  658.             mov ax,1                ;return 1: success
  659.  
  660. p1_done:    pop dx cx bx ds         ;Restore registers
  661.             pop bp                  ;Delete stack frame
  662.             ret 8                   ;Return
  663.  
  664. p1_error:   xor ax,ax               ;Error, return 0
  665.             jmp p1_done
  666.  
  667. EndP        fseek
  668.  
  669. ;****************** ftell() -- Return pointer in buffered file
  670. ;long ftell(int fptr);
  671.  
  672. fptr        = bp+4
  673.  
  674. Proc        ftell
  675.  
  676.             push bp                 ;Set up stack frame
  677.             mov bp,sp
  678.             push ds                 ;Save registers
  679.  
  680.             mov ds,[fptr]           ;DS = seg of file
  681.             cmp [word 14],'FI'      ;Check for signature
  682.             jne p2_error
  683.  
  684.             mov dx,[word 6]         ;DX:AX = current pos
  685.             mov ax,[word 4]         ; = buffer pos + pointer
  686.             add ax,[word 8]
  687.             adc dx,0
  688.  
  689. p2_done:    pop ds                  ;Restore registers
  690.             pop bp                  ;Delete stack frame
  691.             ret 2                   ;Return
  692.  
  693. p2_error:   xor ax,ax               ;Error, return 0
  694.             xor dx,dx
  695.             jmp p2_done
  696.  
  697. EndP        ftell
  698.  
  699. End
  700.  
  701. ~~~C_FREAD
  702. Ideal
  703.  
  704. Extrn       fgetc:near
  705. Public      fread
  706.  
  707. Model Tiny
  708. CodeSeg
  709. P386
  710.  
  711. ;****************** fread() -- Read block from buffered file
  712. ;int fread(int fptr, int nbytes, void *buf);
  713.  
  714. fptr        = bp+8
  715. nbytes      = bp+6
  716. buf         = bp+4
  717.  
  718. Proc        fread
  719.  
  720.             push bp                 ;Set up stack frame
  721.             mov bp,sp
  722.             push bx cx di           ;Save registers
  723.  
  724.             mov bx,[fptr]           ;BX = file ptr
  725.             mov cx,[nbytes]         ;CX = num. of bytes
  726.             mov di,[buf]            ;DI = buffer ptr
  727.             jcxz p1_done            ;Zero bytes, do nothing
  728.  
  729. p1_loop:    push bx                 ;Get char
  730.             call fgetc
  731.             test ax,ax              ;Check for errors
  732.             jl p1_done
  733.             mov [di],al             ;Store byte
  734.             inc di
  735.             loop p1_loop            ;Loop back
  736.  
  737. p1_done:    sub di,[buf]            ;AX = byte count
  738.             xchg ax,di
  739.  
  740.             pop di cx bx            ;Restore registers
  741.             pop bp                  ;Delete stack frame
  742.             ret 6                   ;Return
  743.  
  744. EndP        fread
  745.  
  746. End
  747.  
  748. ~~~C_FWRITE
  749. Ideal
  750.  
  751. Extrn       fputc:near
  752. Public      fwrite
  753.  
  754. Model Tiny
  755. CodeSeg
  756. P386
  757.  
  758. ;****************** fwrite() -- Write block to buffered file
  759. ;int fwrite(int fptr, int nbytes, void *buf);
  760.  
  761. fptr        = bp+8
  762. nbytes      = bp+6
  763. buf         = bp+4
  764.  
  765. Proc        fwrite
  766.  
  767.             push bp                 ;Set up stack frame
  768.             mov bp,sp
  769.             push bx cx si           ;Save registers
  770.  
  771.             mov bx,[fptr]           ;BX = file ptr
  772.             mov cx,[nbytes]         ;CX = num. of bytes
  773.             mov si,[buf]            ;SI = buffer ptr
  774.             mov ax,1                ;Fixup for zero check
  775.             jcxz p1_done            ;Zero bytes, do nothing
  776.  
  777. p1_loop:    lodsb                   ;Load byte
  778.             push bx ax              ;Write char
  779.             call fputc
  780.             test ax,ax              ;Check for errors
  781.             jl p1_done
  782.             loop p1_loop            ;Loop back
  783.  
  784. p1_done:    sub si,[buf]            ;AX = byte count
  785.             dec ax                  ;Subtract 1 if error
  786.             sbb si,0
  787.             xchg ax,si
  788.  
  789.             pop si cx bx            ;Restore registers
  790.             pop bp                  ;Delete stack frame
  791.             ret 6                   ;Return
  792.  
  793. EndP        fwrite
  794.  
  795. End
  796.  
  797. ~~~C_FTRUNC
  798. Ideal
  799.  
  800. Public      ftrunc
  801.  
  802. Model Tiny
  803. CodeSeg
  804. P386
  805.  
  806. ;****************** ftrunc() -- Truncate buffered file at current position
  807. ;int ftrunc(int fptr);
  808.  
  809. fptr        = bp+4
  810.  
  811. Proc        ftrunc
  812.  
  813.             push bp                 ;Set up stack frame
  814.             mov bp,sp
  815.             push ds bx cx dx        ;Save registers
  816.  
  817.             mov ds,[fptr]           ;DS = seg of file
  818.             cmp [word 14],'FI'      ;Check for signature
  819.             jne p1_error
  820.  
  821.             cmp [word 2],0          ;Read only, can't truncate
  822.             je p1_error
  823.  
  824.             mov bx,[word 0]         ;BX = handle
  825.  
  826.             mov ax,4200h            ;Move file ptr
  827.             mov cx,[word 6]         ;CX:DX = current pos
  828.             mov dx,[word 4]         ; = buffer pos + pointer
  829.             add dx,[word 8]
  830.             adc cx,0
  831.             int 21h                 ;DOS call
  832.  
  833.             mov ah,40h              ;Write 0 bytes to file
  834.             xor cx,cx               ;this truncates the file
  835.             int 21h
  836.  
  837.             mov ax,[word 8]         ;Now, byte count = pointer + 1
  838.             inc ax
  839.             mov [word 10],ax
  840.             mov ax,1                ;return 1: success
  841.  
  842. p1_done:    pop dx cx bx ds         ;Restore registers
  843.             pop bp                  ;Delete stack frame
  844.             ret 2                   ;Return
  845.  
  846. p1_error:   xor ax,ax               ;Error, return 0
  847.             jmp p1_done
  848.  
  849. EndP        ftrunc
  850.  
  851. End
  852.  
  853. ~~~C_DELMOV
  854. Ideal
  855.  
  856. Public      fdel,fmove
  857.  
  858. Model Tiny
  859. CodeSeg
  860. P386
  861.  
  862. ;****************** fdel() -- Delete a file
  863. ;int fdel(char *strp);
  864.  
  865. strp        equ bp+4
  866.  
  867. Proc        fdel
  868.  
  869.             push bp                 ;Set up stack frame
  870.             mov bp,sp
  871.             push dx                 ;Save DX
  872.  
  873.             mov ah,41h              ;Delete file
  874.             mov dx,[strp]           ;DX = string pointer
  875.             int 21h                 ;DOS call
  876.  
  877.             sbb ax,ax               ;AX = 1 if ok, 0 if error
  878.             inc ax
  879.  
  880.             pop dx                  ;Restore DX
  881.             pop bp                  ;Delete stack frame
  882.             ret 2                   ;Return
  883.  
  884. EndP        fdel
  885.  
  886. ;****************** fmove() -- Move and/or rename a file
  887. ;int fmove(char *str1, char *str2);
  888.  
  889. str1        equ bp+6
  890. str2        equ bp+4
  891.  
  892. Proc        fmove
  893.  
  894.             push bp                 ;Set up stack frame
  895.             mov bp,sp
  896.             push es dx di           ;Save registers
  897.  
  898.             mov ah,56h              ;Move file
  899.             mov dx,[str1]           ;DX = old name
  900.             push ds                 ;ES = DS
  901.             pop es
  902.             mov di,[str2]           ;ES:DI = new name
  903.             int 21h                 ;DOS call
  904.  
  905.             sbb ax,ax               ;AX = 1 if ok, 0 if error
  906.             inc ax
  907.  
  908.             pop di dx es            ;Restore registers
  909.             pop bp                  ;Delete stack frame
  910.             ret 4                   ;Return
  911.  
  912. EndP        fmove
  913.  
  914. End
  915.  
  916. ~~~C_DIRECT
  917. Ideal
  918.  
  919. Public      getdir,setdir,mkdir,rmdir
  920.  
  921. Model Tiny
  922. CodeSeg
  923. P386
  924.  
  925. ;****************** getdir() -- Get current directory
  926. ;void getdir(char *strp);
  927.  
  928. strp        equ bp+4
  929.  
  930. Proc        getdir
  931.  
  932.             push bp                 ;Set up stack frame
  933.             mov bp,sp
  934.             pusha                   ;Save registers
  935.  
  936.             mov ah,19h              ;Get current drive
  937.             int 21h                 ;DOS call
  938.  
  939.             mov dl,al               ;DL = drive
  940.             mov ah,47h              ;Get current directory
  941.             mov si,[strp]           ;SI = string pointer
  942.             mov [byte si],'\'       ;Add leading slash
  943.             inc si
  944.             int 21h                 ;DOS call
  945.  
  946.             popa                    ;Restore registers
  947.             pop bp                  ;Delete stack frame
  948.             ret 2                   ;Return
  949.  
  950. EndP        getdir
  951.  
  952. ;****************** DIRcall -- Internal: used by setdir,mkdir,rmdir
  953. ;void DIRcall(void);
  954.  
  955. strp        equ bp+4
  956.  
  957. Proc        DIRcall
  958.  
  959.             push dx                 ;Save DX
  960.             mov dx,[strp]           ;DX = string pointer
  961.             int 21h                 ;DOS call
  962.  
  963.             sbb ax,ax               ;AX = 1 if ok, 0 if error
  964.             inc ax
  965.  
  966.             pop dx                  ;Restore DX
  967.             ret                     ;Return
  968.  
  969. EndP        DIRcall
  970.  
  971. ;****************** setdir() -- Set current directory
  972. ;int setdir(char *strp);
  973.  
  974. strp        equ bp+4
  975.  
  976. Proc        setdir
  977.  
  978.             push bp                 ;Set up stack frame
  979.             mov bp,sp
  980.  
  981.             mov ah,3Bh              ;Set current directory
  982.             call DIRcall            ;Directory call
  983.  
  984.             pop bp                  ;Delete stack frame
  985.             ret 2                   ;Return
  986.  
  987. EndP        setdir
  988.  
  989. ;****************** mkdir() -- Create a directory
  990. ;int mkdir(char *strp);
  991.  
  992. strp        equ bp+4
  993.  
  994. Proc        mkdir
  995.  
  996.             push bp                 ;Set up stack frame
  997.             mov bp,sp
  998.  
  999.             mov ah,39h              ;Create directory
  1000.             call DIRcall            ;Directory call
  1001.  
  1002.             pop bp                  ;Delete stack frame
  1003.             ret 2                   ;Return
  1004.  
  1005. EndP        mkdir
  1006.  
  1007. ;****************** rmdir() -- Remove a directory
  1008. ;int rmdir(char *strp);
  1009.  
  1010. strp        equ bp+4
  1011.  
  1012. Proc        rmdir
  1013.  
  1014.             push bp                 ;Set up stack frame
  1015.             mov bp,sp
  1016.  
  1017.             mov ah,3Ah              ;Remove directory
  1018.             call DIRcall            ;Directory call
  1019.  
  1020.             pop bp                  ;Delete stack frame
  1021.             ret 2                   ;Return
  1022.  
  1023. EndP        rmdir
  1024.  
  1025. End
  1026.  
  1027. ~~~C_DRIVE
  1028. Ideal
  1029.  
  1030. Public      getdrive,setdrive
  1031.  
  1032. Model Tiny
  1033. CodeSeg
  1034. P386
  1035.  
  1036. ;****************** getdrive() -- Get current drive
  1037. ;int getdrive(void);
  1038.  
  1039. Proc        getdrive
  1040.  
  1041.             mov ah,19h              ;Get current drive
  1042.             int 21h
  1043.             xor ah,ah               ;Zero AH
  1044.             ret                     ;Return
  1045.  
  1046. EndP        getdrive
  1047.  
  1048. ;****************** setdrive() -- set current drive
  1049. ;void setdrive(int drnum);
  1050.  
  1051. drnum       equ bp+4
  1052.  
  1053. Proc        setdrive
  1054.  
  1055.             push bp                 ;Set up stack frame
  1056.             mov bp,sp
  1057.             pusha                   ;Save registers
  1058.  
  1059.             mov ah,0Eh              ;Set current drive
  1060.             mov dl,[drnum]          ;DL = drive number
  1061.             int 21h
  1062.  
  1063.             popa                    ;Restore registers
  1064.             pop bp                  ;Delete stack frame
  1065.             ret 2                   ;Return
  1066.  
  1067. EndP        setdrive
  1068.  
  1069. End
  1070.  
  1071. ~~~C_DFREE
  1072. Ideal
  1073.  
  1074. Public      getdfree
  1075.  
  1076. Model Tiny
  1077. CodeSeg
  1078. P386
  1079.  
  1080. ;****************** getdfree() -- Return amount of free disk space
  1081. ;long getdfree(int drive);
  1082.  
  1083. drive       equ bp+4
  1084.  
  1085. Proc        getdfree
  1086.  
  1087.             push bp                 ;Set up stack frame
  1088.             mov bp,sp
  1089.             push bx cx              ;Save registers
  1090.  
  1091.             mov dl,[drive]          ;DL = drive
  1092.             mov ah,36h              ;Get free disk space
  1093.             int 21h
  1094.  
  1095.             cwd                     ;DX:AX = AX
  1096.             cmp ax,-1               ;Invalid, return -1
  1097.             je p1_done
  1098.  
  1099.             mul cx                  ;DX:AX = free disk space
  1100.             mul bx                  ; = bytes/sector * sectors/a-unit
  1101.                                     ; * free a-units (allocation units)
  1102.  
  1103. p1_done:    pop cx bx               ;Restore registers
  1104.             pop bp                  ;Delete stack frame
  1105.             ret                     ;Return
  1106.  
  1107. EndP        getdfree
  1108.  
  1109. End
  1110.  
  1111. ~~~C_EXEC
  1112. Ideal
  1113.  
  1114. Extrn       allocmem:near,freemem:near
  1115. Public      exec
  1116.  
  1117. Model Tiny
  1118. CodeSeg
  1119. P386
  1120.  
  1121. ;****************** exec() -- Execute program
  1122. ;int exec(char *prog, char *cmdline);
  1123.  
  1124. prog        equ bp+6
  1125. cmdline     equ bp+4
  1126.  
  1127. Proc        exec
  1128.  
  1129.             push bp                 ;Set up stack frame
  1130.             mov bp,sp
  1131.             push ds es              ;Save all registers
  1132.             pusha
  1133.  
  1134.             push 128                ;Allocate memory for
  1135.             call allocmem           ;the cmdline buffer
  1136.             test ax,ax              ;Out of memory?
  1137.             je p1_done
  1138.             xchg bx,ax              ;Pointer in BX
  1139.  
  1140.             mov si,[prog]           ;SI = program specification
  1141.  
  1142. p1_loop1:   lodsb                   ;Skip past initial spaces
  1143.             cmp al,' '
  1144.             je p1_loop1
  1145.             dec si
  1146.             push si                 ;Save prog string offset
  1147.  
  1148.             mov si,[cmdline]        ;SI = command line
  1149.             mov di,bx               ;DI = string buffer
  1150.             inc di
  1151.             mov cx,126              ;CX = 126
  1152.  
  1153. p1_loop3:   lodsb                   ;Copy the string and
  1154.             test al,al              ;count the chars
  1155.             je p1_cont
  1156.             stosb
  1157.             loop p1_loop3
  1158.  
  1159. p1_cont:    neg cx                  ;CX = char count
  1160.             add cx,126
  1161.             mov [bx],cl             ;Store count
  1162.             mov al,13               ;Store a CR
  1163.             stosb
  1164.  
  1165.             mov ax,[2Eh]            ;word 0 = environment
  1166.             mov [ParBlock],ax
  1167.             mov [ParBlock+2],bx     ;word 2 = command line
  1168.             mov [ParBlock+4],cs     ;word 4 = CS
  1169.             mov [ParBlock+6],5Ch    ;word 6 = 5Ch
  1170.             mov [ParBlock+8],cs     ;word 8 = CS
  1171.             mov [ParBlock+10],6Ch   ;word 10 = 6Ch
  1172.             mov [ParBlock+12],cs    ;word 12 = CS
  1173.  
  1174.             push bx                 ;Save memory pointer
  1175.  
  1176.             push ds                 ;ES:BX = parameter block
  1177.             pop es
  1178.             mov bx,offset ParBlock
  1179.             pop dx                  ;DX = program specification
  1180.             mov ax,4B00h            ;DOS EXEC function
  1181.  
  1182.             mov [StackBuf],sp       ;Save stack pointer
  1183.             mov [StackBuf+2],ss
  1184.  
  1185.             int 21h                 ;Execute program
  1186.  
  1187.             lss sp,[dword cs:StackBuf]  ;Restore stack pointer
  1188.  
  1189.             sbb ax,ax               ;AX = 1 if ok, 0 if error
  1190.             inc ax
  1191.  
  1192.             call freemem            ;Free the memory (BX is still pushed)
  1193.  
  1194. p1_done:    mov es,ax               ;Save AX in ES
  1195.             popa                    ;Restore general registers
  1196.             mov ax,es               ;Restore AX
  1197.             pop es ds               ;Restore segment registers
  1198.             pop bp                  ;Delete stack frame
  1199.             ret 4                   ;Return
  1200.  
  1201. StackBuf    dw 0,0                  ;Save area for SS:SP
  1202.  
  1203. ParBlock    dw 7 dup(0)             ;EXEC parameter block
  1204.  
  1205. EndP        exec
  1206.  
  1207. End
  1208.  
  1209. ~~~C_BITIO
  1210. Ideal
  1211.  
  1212. Extrn       fopen:near,fclose:near,fgetc:near,fputc:near
  1213. Public      bfopen, bfclose, putbit, getbit
  1214. Public      putbits, getbits, putcode, getcode
  1215.  
  1216. Model Tiny
  1217. P386
  1218. CodeSeg
  1219.  
  1220. ;****************** Bit-File Structure . . .
  1221.  
  1222. ;                   Offset  Size    Description
  1223.  
  1224. ;                     0     Word    File handle
  1225. ;                     2     Word    File mode
  1226. ;                     4     Byte    Bit buffer
  1227. ;                     5     Byte    Bit mask
  1228.  
  1229. ;****************** bfopen() -- Open bit-file (returns bit handle)
  1230. ;                               Modes: 0 = read, 1 = write
  1231. ;int bfopen(char *fname, int mode);
  1232.  
  1233. fname       equ bp+6
  1234. mode        equ bp+4
  1235.  
  1236. Proc        bfopen
  1237.  
  1238.             push bp                 ;Set up stack frame
  1239.             mov bp,sp
  1240.             push ds bx cx dx        ;Save registers
  1241.  
  1242.             mov bx,[mode]           ;BX = mode
  1243.             and bx,1
  1244.             mov cx,bx               ;Save mode
  1245.             imul bx,3               ;Mode for fopen()
  1246.  
  1247.             push [word fname] bx    ;Open the file
  1248.             call fopen
  1249.             test ax,ax              ;Check for errors
  1250.             jz p1_err1
  1251.             xchg dx,ax              ;DX = file
  1252.  
  1253.             mov ah,48h              ;Allocate memory
  1254.             mov bx,1                ;16 bytes
  1255.             int 21h                 ;DOS call
  1256.             jc p1_err2              ;Check for errors
  1257.  
  1258.             mov ds,ax               ;DS = bit-file
  1259.             mov [0],dx              ;Set file handle...
  1260.             mov [2],cx              ;file mode...
  1261.             mov [word 4],8000h      ;buffer/mask...
  1262.  
  1263. p1_done:    pop dx cx bx ds         ;Restore registers
  1264.             pop bp                  ;Delete stack frame
  1265.             ret 4                   ;Return
  1266.  
  1267. p1_err2:    push dx                 ;Out of memory, close file
  1268.             call fclose
  1269.  
  1270. p1_err1:    xor ax,ax               ;Error, return 0
  1271.             jmp p1_done
  1272.  
  1273. EndP        bfopen
  1274.  
  1275. ;****************** bfclose() -- Close bit-file
  1276. ;void bfclose(int bfp);
  1277.  
  1278. bfp         equ bp+4
  1279.  
  1280. Proc        bfclose
  1281.  
  1282.             push bp                 ;Set up stack frame
  1283.             mov bp,sp
  1284.             pusha                   ;Save all registers
  1285.             push es
  1286.  
  1287.             mov es,[bfp]            ;ES = bit-file
  1288.  
  1289.             cmp [word es:2],1       ;Input file?
  1290.             jne p2_skip
  1291.             cmp [byte es:5],80h     ;Buffer empty?
  1292.             je p2_skip
  1293.  
  1294.             push [word es:0]        ;Flush buffer
  1295.             push [word es:4]
  1296.             call fputc
  1297.  
  1298. p2_skip:    push [word es:0]        ;Close file
  1299.             call fclose
  1300.             mov ah,49h              ;Free memory
  1301.             int 21h
  1302.  
  1303.             pop es                  ;Restore registers
  1304.             popa
  1305.             pop bp                  ;Delete stack frame
  1306.             ret 2                   ;Return
  1307.  
  1308. EndP        bfclose
  1309.  
  1310. ;****************** getbit() -- Get bit from bit-file
  1311. ;int getbit(int bfp);
  1312.  
  1313. bfp         equ bp+4
  1314.  
  1315. Proc        getbit
  1316.  
  1317.             push bp                 ;Set up stack frame
  1318.             mov bp,sp
  1319.             push es                 ;Save registers
  1320.  
  1321.             mov es,[bfp]            ;ES = bit-file
  1322.             cmp [word es:2],0       ;Output file, can't input
  1323.             jne p3_done
  1324.             cmp [byte es:5],80h     ;Buffer empty?
  1325.             jne p3_skip1
  1326.  
  1327.             push [word es:0]        ;Get char
  1328.             call fgetc
  1329.             mov [es:4],al           ;Save char
  1330.  
  1331. p3_skip1:   mov al,[es:4]           ;Get bit
  1332.             and al,[es:5]
  1333.             shr [byte es:5],1       ;Move to next bit
  1334.             jnz p3_skip2            ;Finished a byte?
  1335.             mov [byte es:5],80h     ;Set mask to 80h
  1336.  
  1337. p3_skip2:   test al,al              ;AX = 1 if nonzero,
  1338.             setnz al                ;or 0 if zero
  1339.             cbw
  1340.  
  1341. p3_done:    pop es                  ;Restore registers
  1342.             pop bp                  ;Delete stack frame
  1343.             ret 2                   ;Return
  1344.  
  1345. EndP        getbit
  1346.  
  1347. ;****************** putbit() -- Put bit to bit-file
  1348. ;void putbit(int bfp, int bit);
  1349.  
  1350. bfp         equ bp+6
  1351. bit         equ bp+4
  1352.  
  1353. Proc        putbit
  1354.  
  1355.             push bp                 ;Set up stack frame
  1356.             mov bp,sp
  1357.             pusha                   ;Save all registers
  1358.             push es
  1359.  
  1360.             mov es,[bfp]            ;ES = bit-file
  1361.             cmp [word es:2],1       ;Input file, can't output
  1362.             jne p4_done
  1363.  
  1364.             cmp [word bit],0        ;Check bit
  1365.             jz p4_skip
  1366.             mov al,[es:5]           ;Add bit to buffer
  1367.             or [es:4],al
  1368.  
  1369. p4_skip:    shr [byte es:5],1       ;Move to next bit
  1370.             jnz p4_done             ;Finished a byte?
  1371.  
  1372.             push [word es:0]        ;Put byte to file
  1373.             push [word es:4]
  1374.             call fputc
  1375.             mov [word es:4],8000h   ;Buf = 0, Mask = 80h
  1376.  
  1377. p4_done:    pop es                  ;Restore registers
  1378.             popa
  1379.             pop bp                  ;Delete stack frame
  1380.             ret 4                   ;Return
  1381.  
  1382. EndP        putbit
  1383.  
  1384. ;****************** getbits() -- Get bits from bit-file
  1385. ;int getbits(int bfp, int count);
  1386.  
  1387. bfp         equ bp+6
  1388. count       equ bp+4
  1389.  
  1390. Proc        getbits
  1391.  
  1392.             push bp                 ;Set up stack frame
  1393.             mov bp,sp
  1394.             push es cx dx           ;Save registers
  1395.  
  1396.             mov es,[bfp]            ;ES = bit-file
  1397.             cmp [word es:2],0       ;Output file, can't input
  1398.             jne p5_done
  1399.  
  1400.             mov cx,[count]          ;CX = bit count
  1401.             xor dx,dx               ;Zero buffer
  1402.  
  1403. p5_loop:    cmp [byte es:5],80h     ;Buffer empty?
  1404.             jne p5_skip1
  1405.  
  1406.             push [word es:0]        ;Get char
  1407.             call fgetc
  1408.             mov [es:4],al           ;Save char
  1409.  
  1410. p5_skip1:   mov al,[es:4]           ;Get bit
  1411.             and al,[es:5]
  1412.             ror [byte es:5],1       ;Move to next bit
  1413.  
  1414. p5_skip2:   add dx,dx               ;Shift over
  1415.             test al,al              ;If bit = 1,
  1416.             jz $+3                  ;then add it in
  1417.             inc dx
  1418.             loop p5_loop            ;Loop back
  1419.  
  1420.             xchg ax,dx              ;AX = result
  1421.  
  1422. p5_done:    pop dx cx es            ;Restore registers
  1423.             pop bp                  ;Delete stack frame
  1424.             ret 4                   ;Return
  1425.  
  1426. EndP        getbits
  1427.  
  1428. ;****************** putbits() -- Put bits to bit-file
  1429. ;int putbits(int bfp, int code, int count);
  1430.  
  1431. bfp         equ bp+8
  1432. code        equ bp+6
  1433. count       equ bp+4
  1434.  
  1435. Proc        putbits
  1436.  
  1437.             push bp                 ;Set up stack frame
  1438.             mov bp,sp
  1439.             pusha                   ;Save all registers
  1440.  
  1441.             mov bx,[bfp]            ;BX = bit-file
  1442.             mov cx,[count]          ;CX = bit count
  1443.             mov dx,[code]           ;DX = code
  1444.             ror dx,cl               ;Put at left
  1445.  
  1446. p6_loop:    add dx,dx               ;Shift out bit
  1447.             sbb ax,ax               ;AX = bit
  1448.             push bx ax              ;Put bit
  1449.             call putbit
  1450.             loop p6_loop            ;Loop back
  1451.  
  1452.             popa                    ;Restore registers
  1453.             pop bp                  ;Delete stack frame
  1454.             ret 6                   ;Return
  1455.  
  1456. EndP        putbits
  1457.  
  1458. ;****************** getcode() -- Get optimal code from bit-file
  1459. ;int getcode(int bfp, int max);  'max' is number of possible codes
  1460.  
  1461. bfp         equ bp+6
  1462. max         equ bp+4
  1463.  
  1464. Proc        getcode
  1465.  
  1466.             push bp                 ;Set up stack frame
  1467.             mov bp,sp
  1468.             push bx cx dx si        ;Save registers
  1469.  
  1470.             bsr cx,[max]            ;CX = log2(max) + 1;
  1471.             jz p7_done              ;Quit on 0
  1472.  
  1473.             mov si,1                ;SI = 2^CX - max
  1474.             shl si,cl
  1475.             sub si,[max]
  1476.  
  1477.             mov bx,[bfp]            ;BX = bit-file
  1478.             dec cx                  ;CX = count (log2(max))
  1479.  
  1480.             push bx cx              ;Get bits
  1481.             call getbits
  1482.             xchg ax,dx              ;Result in DX
  1483.  
  1484.             cmp dx,si               ;DX >= SI?
  1485.             jb p7_done
  1486.  
  1487.             push bx                 ;Add in another bit
  1488.             call getbit
  1489.             add dx,dx
  1490.             add dx,ax
  1491.             sub dx,si               ;Subtract out SI
  1492.  
  1493. p7_done:    xchg ax,dx              ;AX = result
  1494.             pop si dx cx bx         ;Restore registers
  1495.             pop bp                  ;Delete stack frame
  1496.             ret 4                   ;Return
  1497.  
  1498. EndP        getcode
  1499.  
  1500. ;****************** putcode() -- Put optimal code to bit-file
  1501. ;                                'max' is number of possible codes
  1502. ;int putcode(int bfp, int code, int max);
  1503.  
  1504. bfp         equ bp+8
  1505. code        equ bp+6
  1506. max         equ bp+4
  1507.  
  1508. Proc        putcode
  1509.  
  1510.             push bp                 ;Set up stack frame
  1511.             mov bp,sp
  1512.             pusha                   ;Save all registers
  1513.  
  1514.             bsr cx,[max]            ;CX = log2(max) + 1;
  1515.             jz p7_done              ;Quit on 0
  1516.  
  1517.             mov si,1                ;SI = 2^CX - max
  1518.             shl si,cl
  1519.             sub si,[max]
  1520.  
  1521.             mov dx,[code]           ;DX = code
  1522.             dec cx                  ;CX = bit count
  1523.  
  1524.             cmp dx,si               ;DX >= SI?
  1525.             jb p8_skip
  1526.             inc cx                  ;One more bit
  1527.             add dx,si               ;and add in SI
  1528.  
  1529. p8_skip:    push [word bfp] dx cx   ;Output bit code
  1530.             call putbits
  1531.  
  1532. p8_done:    popa                    ;Restore registers
  1533.             pop bp                  ;Delete stack frame
  1534.             ret 4                   ;Return
  1535.  
  1536. EndP        putcode
  1537.  
  1538. End
  1539.  
  1540. ~~~C_MEMORY
  1541. Ideal
  1542.  
  1543. Extrn       TopByte:Word
  1544. Public      allocmem,freemem,getmfree
  1545.  
  1546. Model Tiny
  1547. P386
  1548. CodeSeg
  1549.  
  1550. ;****************** allocmem() -- Allocate memory
  1551. ;void *allocmem(unsigned nbytes);
  1552.  
  1553. nbytes      equ bp+4
  1554.  
  1555. Proc        allocmem
  1556.  
  1557.             push bp                 ;Set up stack frame
  1558.             mov bp,sp
  1559.             pusha                   ;Save registers
  1560.             push es
  1561.  
  1562.             mov dx,[bp+4]           ;DX = num. of bytes + 3
  1563.             add dx,3
  1564.             mov bx,offset TopByte   ;BX = first MCB
  1565.  
  1566. p1_loop:    mov cl,[bx+2]           ;CX = flag byte
  1567.             test cl,1               ;Not free, loop
  1568.             jnz p1_lb
  1569.             mov ax,[bx]             ;AX = size
  1570.             cmp ax,dx               ;Big enough?
  1571.             jae p1_gotit
  1572.  
  1573. p1_lb:      test cl,2               ;Last block?
  1574.             jnz p1_nope             ;Out of memory
  1575.             add bx,[bx]             ;Next block
  1576.             jmp p1_loop             ;Loop back
  1577.  
  1578. p1_gotit:   sub ax,3                ;Check for snug fit,
  1579.             cmp ax,dx               ;that is, too little
  1580.             jbe p1_snug             ;excess to split it
  1581.  
  1582.             sub ax,dx               ;AX = excess
  1583.             add ax,3
  1584.  
  1585.             mov si,bx               ;SI = split point
  1586.             add si,dx
  1587.             mov [si],ax             ;Set size of excess block
  1588.             mov [si+2],cl           ;Set flags to original values
  1589.  
  1590.             mov [bx],dx             ;Set size of present block
  1591.             mov [byte bx+2],1       ;Set flags: allocated, not last
  1592.             jmp p1_finish
  1593.  
  1594. p1_snug:    or [byte bx+2],1        ;Set allocated flag
  1595.  
  1596. p1_finish:  add bx,3                ;BX = offset of memory block
  1597.  
  1598. p1_done:    mov [bp-2],bx           ;Change pushed AX
  1599.             pop es                  ;Restore registers
  1600.             popa
  1601.             pop bp                  ;Delete stack frame
  1602.             ret 2                   ;Return
  1603.  
  1604. p1_nope:    xor bx,bx               ;Return null pointer
  1605.             jmp p1_done
  1606.  
  1607. EndP        allocmem
  1608.  
  1609. ;****************** freemem() -- Free memory
  1610. ;void freemem(void *ptr);
  1611.  
  1612. ptr         equ bp+4
  1613.  
  1614. Proc        freemem
  1615.  
  1616.             push bp                 ;Set up stack frame
  1617.             mov bp,sp
  1618.             pusha                   ;Save registers
  1619.  
  1620.             mov dx,[ptr]            ;DX = pointer
  1621.             sub dx,3                ;Point to MCB
  1622.             mov bx,offset TopByte   ;BX = first MCB
  1623.             xor si,si               ;Zero previous ptr.
  1624.  
  1625. p2_loop:    cmp bx,dx               ;Found it?
  1626.             je p2_gotit
  1627.  
  1628.             test [byte bx+2],2      ;Last block?
  1629.             jnz p2_done
  1630.             mov si,bx               ;Save block
  1631.             add bx,[bx]             ;Next block
  1632.             jmp p2_loop             ;Loop back
  1633.  
  1634. p2_gotit:   mov di,bx               ;DI = next block
  1635.             add di,[bx]
  1636.  
  1637.             test [byte bx+2],2      ;Next block allocated
  1638.             jnz p2_cont1            ;or nonexistent, can't
  1639.             mov cl,[di+2]           ;merge with it
  1640.             test cl,1
  1641.             jnz p2_done
  1642.  
  1643.             mov ax,[di]             ;Merge blocks: sum sizes,
  1644.             add [bx],ax             ;set flags of second one
  1645.             mov [bx+2],cl
  1646.  
  1647. p2_cont1:   and [byte bx+2],0FEh    ;Reset allocated flag
  1648.  
  1649.             test si,si              ;Prev. block allocated
  1650.             jz p2_done              ;or nonexistent, can't
  1651.             mov cl,[si+2]           ;merge with it
  1652.             test cl,1
  1653.             jnz p2_done
  1654.  
  1655.             mov ax,[bx]             ;Merge blocks: sum sizes,
  1656.             add [si],ax             ;set flags of second one
  1657.             mov cl,[bx+2]
  1658.             mov [si+2],cl
  1659.  
  1660. p2_done:    popa                    ;Restore registers
  1661.             pop bp                  ;Delete stack frame
  1662.             ret 2                   ;Return
  1663.  
  1664. EndP        freemem
  1665.  
  1666. ;****************** getmfree() -- Return largest free memory block
  1667. ;unsigned getmfree(void);
  1668.  
  1669. ptr         equ bp+4
  1670.  
  1671. Proc        getmfree
  1672.  
  1673.             push bp                 ;Set up stack frame
  1674.             mov bp,sp
  1675.             push bx                 ;Save registers
  1676.  
  1677.             mov bx,offset TopByte   ;BX = first MCB
  1678.             xor ax,ax               ;Zero counter
  1679.  
  1680. p3_loop:    test [byte bx+2],1      ;Not free, skip
  1681.             jnz p3_skip
  1682.             cmp ax,[bx]             ;Biggest so far?
  1683.             jae p3_skip
  1684.             mov ax,[bx]             ;Save largest block
  1685.  
  1686. p3_skip:    test [byte bx+2],2      ;Last block?
  1687.             jnz p3_done
  1688.             add bx,[bx]             ;Next block
  1689.             jmp p3_loop             ;Loop back
  1690.  
  1691. p3_done:    sub ax,3                ;Adjust to true size
  1692.             pop bx                  ;Restore registers
  1693.             pop bp                  ;Delete stack frame
  1694.             ret                     ;Return
  1695.  
  1696. EndP        getmfree
  1697.  
  1698. End
  1699.  
  1700. ~~~C_FARMEM
  1701. Ideal
  1702.  
  1703. Public      faralloc,farfree,getfarfree
  1704.  
  1705. Model Tiny
  1706. P386
  1707. CodeSeg
  1708.  
  1709. ;****************** faralloc() -- Allocate far memory
  1710. ;int faralloc(int nparas);
  1711.  
  1712. nparas      equ bp+4
  1713.  
  1714. Proc        faralloc
  1715.  
  1716.             push bp                 ;Set up stack frame
  1717.             mov bp,sp
  1718.             push bx                 ;Save BX
  1719.  
  1720.             mov ah,48h              ;Allocate memory
  1721.             mov bx,[nparas]         ;BX = paras
  1722.             int 21h                 ;DOS call
  1723.  
  1724.             jnc $+4                 ;No error, return pointer
  1725.             xor ax,ax               ;Error, return 0
  1726.  
  1727.             pop bx                  ;Restore BX
  1728.             pop bp                  ;Delete stack frame
  1729.             ret 2                   ;Return
  1730.  
  1731. EndP        faralloc
  1732.  
  1733. ;****************** farfree() -- Free far memory
  1734. ;void farfree(int ptr);
  1735.  
  1736. ptr         equ bp+4
  1737.  
  1738. Proc        farfree
  1739.  
  1740.             push bp                 ;Set up stack frame
  1741.             mov bp,sp
  1742.             push es ax              ;Save registers
  1743.  
  1744.             mov ah,4Ah              ;Free memory
  1745.             mov es,[ptr]            ;ES = pointer
  1746.             int 21h                 ;DOS call
  1747.  
  1748.             pop ax es               ;Restore registers
  1749.             pop bp                  ;Delete stack frame
  1750.             ret 2                   ;Return
  1751.  
  1752. EndP        farfree
  1753.  
  1754. ;****************** getfarfree() -- Return largest free far memory block
  1755. ;unsigned getfarfree(void);
  1756.  
  1757. ptr         equ bp+4
  1758.  
  1759. Proc        getfarfree
  1760.  
  1761.             push bp                 ;Set up stack frame
  1762.             mov bp,sp
  1763.             push bx                 ;Save registers
  1764.  
  1765.             mov ah,48h              ;Allocate memory
  1766.             mov bx,-1               ;-1 is invalid
  1767.             int 21h                 ;DOS call (returns an error)
  1768.             xchg ax,bx              ;AX = size of largest free block
  1769.  
  1770.             pop bx                  ;Restore registers
  1771.             pop bp                  ;Delete stack frame
  1772.             ret                     ;Return
  1773.  
  1774. EndP        getfarfree
  1775.  
  1776. End
  1777.  
  1778. ~~~C_ATOI
  1779. Ideal
  1780.  
  1781. Public      atoi,atol
  1782.  
  1783. Model Tiny
  1784. CodeSeg
  1785. P386
  1786.  
  1787. ;****************** atoi() -- Convert string to int
  1788. ;int atoi(char *strp);
  1789.  
  1790. strp        equ bp+4
  1791.  
  1792. Proc        atoi
  1793.  
  1794.             push bp                 ;Set up stack frame
  1795.             mov bp,sp
  1796.  
  1797.             push dx [word strp]     ;Save DX, call atol
  1798.             call atol
  1799.  
  1800.             pop dx                  ;Restore DX
  1801.             pop bp                  ;Delete stack frame
  1802.             ret 2                   ;Return
  1803.  
  1804. EndP        atoi
  1805.  
  1806. ;****************** atol() -- Convert string to long
  1807. ;long atol(char *strp);
  1808.  
  1809. strp        equ bp+4
  1810.  
  1811. Proc        atol
  1812.  
  1813.             push bp                 ;Set up stack frame
  1814.             mov bp,sp
  1815.             push si di ebx ecx      ;Save registers
  1816.  
  1817.             mov si,[strp]           ;SI = string
  1818.  
  1819.             xor ecx,ecx             ;ECX = 0
  1820.             xor ebx,ebx             ;EBX = 0
  1821.  
  1822. p1_ploop:   mov bl,[si]             ;Load char
  1823.             inc si
  1824.             cmp bl,' '              ;Loop while char is space
  1825.             je p1_ploop             ;(20h, or 09h thru 0Dh)
  1826.             cmp bl,9
  1827.             jna p1_cont
  1828.             cmp bl,13
  1829.             jbe p1_ploop
  1830.  
  1831. p1_cont:    xor di,di               ;DI = 0
  1832.             cmp bl,'+'              ;If char = '+', ignore
  1833.             je p1_loop
  1834.             cmp bl,'-'              ;If char <> '-', keep it
  1835.             jne p1_skip
  1836.             inc di                  ;Set negative flag
  1837.  
  1838. p1_loop:    mov bl,[si]             ;Load char
  1839.             inc si
  1840.  
  1841. p1_skip:    cmp bl,'9'              ;Not a digit, finish
  1842.             ja p1_finish
  1843.             sub bl,'0'
  1844.             jc p1_finish
  1845.  
  1846.             imul ecx,10             ;Multiply by 10
  1847.             add ecx,ebx             ;Add in digit...
  1848.             jmp p1_loop             ;Loop back
  1849.  
  1850. p1_finish:  xchg ax,cx              ;DX:AX = result
  1851.             shr ecx,16
  1852.             mov dx,cx
  1853.             dec di                  ;Positive, don't negate
  1854.             jl p1_done
  1855.  
  1856.             neg dx                  ;Negate the result
  1857.             neg ax
  1858.             sbb dx,0
  1859.  
  1860. p1_done:    pop ecx ebx di si       ;Restore registers
  1861.             pop bp                  ;Delete stack frame
  1862.             ret 2                   ;Return
  1863.  
  1864. EndP        atol
  1865.  
  1866. End
  1867.  
  1868. ~~~C_ITOA
  1869. Ideal
  1870.  
  1871. Public      itoa
  1872.  
  1873. Model Tiny
  1874. CodeSeg
  1875. P386
  1876.  
  1877. ;****************** itoa() -- Convert int to string
  1878. ;void itoa(int n, char *strp);
  1879.  
  1880. n           equ bp+6
  1881. strp        equ bp+4
  1882.  
  1883. Proc        itoa
  1884.  
  1885.             push bp                 ;Set up stack frame
  1886.             mov bp,sp
  1887.             pusha                   ;Save all registers
  1888.  
  1889.             mov ax,[n]              ;AX = n
  1890.             mov di,[strp]           ;DI = string pointer
  1891.  
  1892.             test ax,ax              ;Negative?
  1893.             jge p1_noneg
  1894.             mov [byte di],'-'       ;Store minus sign
  1895.             inc di
  1896.             neg ax                  ;Make it positive
  1897.  
  1898. p1_noneg:   xor cx,cx               ;Zero CX
  1899.             test ax,ax              ;Check for zero
  1900.             jnz p1_nozero
  1901.  
  1902.             push '0'                ;Push a zero
  1903.             inc cx                  ;One digit
  1904.             jmp p1_ploop
  1905.  
  1906. p1_nozero:  mov si,10               ;SI = 10
  1907.  
  1908. p1_dloop:   xor dx,dx               ;Divide by 10
  1909.             div si
  1910.             mov bl,dl               ;Remainder in BL
  1911.             add bl,30h              ;Convert to digit
  1912.             push bx                 ;Push digit
  1913.             inc cx
  1914.             test ax,ax              ;Loop back
  1915.             jnz p1_dloop
  1916.  
  1917. p1_ploop:   pop ax                  ;Pop digit
  1918.             mov [di],al             ;Store digit
  1919.             inc di
  1920.             loop p1_ploop           ;Loop back
  1921.  
  1922.             mov [byte di],0         ;Add the null byte
  1923.  
  1924.             popa                    ;Restore registers
  1925.             pop bp                  ;Delete stack frame
  1926.             ret 4                   ;Return
  1927.  
  1928. EndP        itoa
  1929.  
  1930. End
  1931.  
  1932. ~~~C_LTOA
  1933. Ideal
  1934.  
  1935. Extrn       itoa:near
  1936. Public      ltoa
  1937.  
  1938. Model Tiny
  1939. CodeSeg
  1940. P386
  1941.  
  1942. ;****************** ltoa() -- Convert long to string
  1943. ;void ltoa(long n, char *strp);
  1944.  
  1945. n           equ bp+6
  1946. strp        equ bp+4
  1947.  
  1948. Proc        ltoa
  1949.  
  1950.             push bp                 ;Set up stack frame
  1951.             mov bp,sp
  1952.             pushad                  ;Save all registers
  1953.  
  1954.             mov eax,[n]             ;EAX = n
  1955.             mov di,[strp]           ;DI = string pointer
  1956.  
  1957.             test eax,eax            ;Negative?
  1958.             jge p1_noneg
  1959.             mov [byte di],'-'       ;Store minus sign
  1960.             inc di
  1961.             neg eax                 ;Make it positive
  1962.  
  1963. p1_noneg:   xor cx,cx               ;Zero CX
  1964.             test eax,eax            ;Check for zero
  1965.             jnz p1_nozero
  1966.  
  1967.             push '0'                ;Push a zero
  1968.             inc cx                  ;One digit
  1969.             jmp p1_ploop
  1970.  
  1971. p1_nozero:  mov si,10               ;SI = 10
  1972.  
  1973. p1_dloop:   xor edx,edx             ;Divide by 10
  1974.             div si
  1975.             mov bl,dl               ;Remainder in BL
  1976.             add bl,30h              ;Convert to digit
  1977.             push bx                 ;Push digit
  1978.             inc cx
  1979.             test eax,eax            ;Loop back
  1980.             jnz p1_dloop
  1981.  
  1982. p1_ploop:   pop ax                  ;Pop digit
  1983.             mov [di],al             ;Store digit
  1984.             inc di
  1985.             loop p1_ploop           ;Loop back
  1986.  
  1987.             mov [byte di],0         ;Add the null byte
  1988.  
  1989.             popad                   ;Restore registers
  1990.             pop bp                  ;Delete stack frame
  1991.             ret 6                   ;Return
  1992.  
  1993. EndP        ltoa
  1994.  
  1995. End
  1996.  
  1997. ~~~C_PUTS
  1998. Ideal
  1999.  
  2000. Extrn       PUT_CHAR:near
  2001. Public      puts,xputs
  2002.  
  2003. Model Tiny
  2004. CodeSeg
  2005. P386
  2006.  
  2007. ;****************** puts() -- Print string
  2008. ;void puts(char *strp);
  2009.  
  2010. strp        equ bp+4
  2011.  
  2012. Proc        puts
  2013.  
  2014.             push bp                 ;Set up stack frame
  2015.             mov bp,sp
  2016.             pusha                   ;Save all registers
  2017.  
  2018.             mov si,[strp]           ;SI = string pointer
  2019.  
  2020. p1_loop:    lodsb                   ;Get char
  2021.             test al,al              ;Check for null
  2022.             jz p1_done
  2023.             call PUT_CHAR           ;Output char
  2024.             jmp p1_loop             ;Loop back
  2025.  
  2026. p1_done:    popa                    ;Restore registers
  2027.             pop bp                  ;Delete stack frame
  2028.             ret 2                   ;Return
  2029.  
  2030. EndP        puts
  2031.  
  2032. ;****************** xputs() -- Print string, generalized
  2033. ;void xputs(void *func, int strp);
  2034.  
  2035. func        equ bp+6
  2036. strp        equ bp+4
  2037.  
  2038. Proc        xputs
  2039.  
  2040.             push bp                 ;Set up stack frame
  2041.             mov bp,sp
  2042.             pusha                   ;Save all registers
  2043.  
  2044.             mov si,[strp]           ;SI = string pointer
  2045.             mov bx,[func]           ;BX = function
  2046.  
  2047. p2_loop:    lodsb                   ;Get char
  2048.             test al,al              ;Check for null
  2049.             jz p2_done
  2050.             push ax                 ;Output char
  2051.             call bx
  2052.             jmp p2_loop             ;Loop back
  2053.  
  2054. p2_done:    popa                    ;Restore registers
  2055.             pop bp                  ;Delete stack frame
  2056.             ret 4                   ;Return
  2057.  
  2058. EndP        xputs
  2059.  
  2060. End
  2061.  
  2062. ~~~C_FPUTS
  2063. Ideal
  2064.  
  2065. Extrn       fputc:near
  2066. Public      fputs
  2067.  
  2068. Model Tiny
  2069. CodeSeg
  2070. P386
  2071.  
  2072. ;****************** fputs() -- Print string to file
  2073. ;int fputs(int fp, char *strp);
  2074.  
  2075. fp          equ bp+6
  2076. strp        equ bp+4
  2077.  
  2078. Proc        fputs
  2079.  
  2080.             push bp                 ;Set up stack frame
  2081.             mov bp,sp
  2082.             push bx si              ;Save registers
  2083.  
  2084.             mov si,[strp]           ;SI = string pointer
  2085.             mov bx,[fp]             ;BX = file pointer
  2086.  
  2087. p1_loop:    lodsb                   ;Get char
  2088.             test al,al              ;Check for null
  2089.             jz p1_done
  2090.             push bx ax              ;Output char:
  2091.             call fputc              ;fputc(fp, AX);
  2092.             test ax,ax
  2093.             jnl p1_loop             ;Loop back
  2094.  
  2095. p1_done:    pop si bx               ;Restore registers
  2096.             pop bp                  ;Delete stack frame
  2097.             ret 4                   ;Return
  2098.  
  2099. EndP        fputs
  2100.  
  2101. End
  2102.  
  2103. ~~~C_GETS
  2104. Ideal
  2105.  
  2106. Public      gets,xgets
  2107.  
  2108. Model Tiny
  2109. CodeSeg
  2110. P386
  2111.  
  2112. ;****************** gets() -- Get string
  2113. ;void gets(char *strp, int max);
  2114.  
  2115. strp        equ bp+6
  2116. max         equ bp+4
  2117.  
  2118. Proc        gets
  2119.  
  2120.             push bp                 ;Set up stack frame
  2121.             mov bp,sp
  2122.             pusha                   ;Save all registers
  2123.             push es
  2124.  
  2125.             mov di,[strp]           ;DI = string pointer
  2126.             mov cx,[max]            ;CX = max string length
  2127.             dec cx
  2128.  
  2129. p1_loop:    xor ax,ax               ;Get key
  2130.             int 16h
  2131.             test al,al              ;Ignore extended keys
  2132.             jz p1_loop
  2133.             cmp al,8                ;Backspace?
  2134.             je p1_bksp
  2135.  
  2136.             int 29h                 ;Show char (on screen)
  2137.             cmp al,13               ;<Enter> = done
  2138.             je p1_done
  2139.             jcxz p1_loop            ;Maxed out, don't store
  2140.             mov [di],al             ;Store char
  2141.             inc di
  2142.             dec cx                  ;Decrement maximum
  2143.             jmp p1_loop             ;Loop back
  2144.  
  2145. p1_bksp:    cmp di,[strp]           ;At beginning, do nothing
  2146.             je p1_loop
  2147.             dec di                  ;Decrement string pointer
  2148.             inc cx                  ;Increment maximum
  2149.  
  2150.             push cx                 ;Save CX
  2151.             mov ah,0Fh              ;Get video page
  2152.             int 10h
  2153.             mov ah,3                ;Get cursor position
  2154.             int 10h                 ;in DH/DL
  2155.             dec dx                  ;Move left one column
  2156.             test dl,dl              ;if at zero moves up too
  2157.             jnl p1_nowrap
  2158.  
  2159.             push 0                  ;DL = last column
  2160.             pop es
  2161.             mov dl,[es:044Ah]
  2162.             dec dx
  2163.  
  2164. p1_nowrap:  mov ah,2                ;Set cursor position
  2165.             int 10h
  2166.             mov ax,0A20h            ;Clear char at current
  2167.             mov cx,1                ;cursor position
  2168.             int 10h
  2169.             pop cx                  ;Restore CX
  2170.             jmp p1_loop             ;Loop back
  2171.  
  2172. p1_done:    mov al,10               ;Output LF
  2173.             int 29h
  2174.             mov [byte di],0         ;Terminate string
  2175.             pop es                  ;Restore registers
  2176.             popa
  2177.             pop bp                  ;Delete stack frame
  2178.             ret 4                   ;Return
  2179.  
  2180. EndP        gets
  2181.  
  2182. ;****************** xgets() -- Get string, generalized
  2183. ;void xgets(void *func, char *strp, int max, int term);
  2184.  
  2185. strp        equ bp+10
  2186. func        equ bp+8
  2187. max         equ bp+6
  2188. term        equ bp+4
  2189.  
  2190. Proc        xgets
  2191.  
  2192.             push bp                 ;Set up stack frame
  2193.             mov bp,sp
  2194.             pusha                   ;Save all registers
  2195.  
  2196.             mov di,[strp]           ;DI = string pointer
  2197.             mov bx,[func]           ;BX = function
  2198.             mov cx,[max]            ;CX = max string length
  2199.             dec cx
  2200.             mov dx,[term]           ;DX = terminator
  2201.  
  2202. p2_loop:    call bx                 ;Get char
  2203.             cmp al,dl               ;Check for terminator
  2204.             je p2_done
  2205.             jcxz p1_loop            ;Maxed out, don't store
  2206.             mov [di],al             ;Store char
  2207.             inc di
  2208.             dec cx                  ;Decrement maximum
  2209.             jmp p2_loop             ;Loop back
  2210.  
  2211. p2_done:    mov [byte di],0         ;Terminate string
  2212.             popa                    ;Restore registers
  2213.             pop bp                  ;Delete stack frame
  2214.             ret 8                   ;Return
  2215.  
  2216. EndP        xgets
  2217.  
  2218. End
  2219.  
  2220. ~~~C_FGETS
  2221. Ideal
  2222.  
  2223. Extrn       fgetc:near
  2224. Public      fgets
  2225.  
  2226. Model Tiny
  2227. CodeSeg
  2228. P386
  2229.  
  2230. ;****************** fgets() -- Get string from file
  2231. ;void fgets(int fp, char *strp, int max);
  2232.  
  2233. fp          equ bp+8
  2234. strp        equ bp+6
  2235. max         equ bp+4
  2236.  
  2237. Proc        fgets
  2238.  
  2239.             push bp                 ;Set up stack frame
  2240.             mov bp,sp
  2241.             push bx cx dx di        ;Save all registers
  2242.  
  2243.             mov di,[strp]           ;DI = string pointer
  2244.             mov bx,[fp]             ;BX = file pointer
  2245.             mov cx,[max]            ;CX = max string length
  2246.             dec cx
  2247.  
  2248. p1_loop:    push bx                 ;Get char
  2249.             call fgetc
  2250.             test ax,ax              ;Check for EOF
  2251.             jl p1_quit
  2252.             cmp al,13               ;CR = done
  2253.             je p1_done
  2254.             jcxz p1_loop            ;Maxed out, don't store
  2255.             mov [di],al             ;Store char
  2256.             inc di
  2257.             dec cx                  ;Decrement maximum
  2258.             jmp p1_loop             ;Loop back
  2259.  
  2260. p1_done:    push bx                 ;Remove LF
  2261.             call fgetc
  2262.             xor ax,ax
  2263. p1_quit:    mov [byte di],0         ;Terminate string
  2264.             pop di dx cx bx         ;Restore registers
  2265.             pop bp                  ;Delete stack frame
  2266.             ret 6                   ;Return
  2267.  
  2268. EndP        fgets
  2269.  
  2270. End
  2271.  
  2272. ~~~C_PRTBUF
  2273. Ideal
  2274.  
  2275. Public      PRT_BUF
  2276.  
  2277. Model Tiny
  2278. CodeSeg
  2279. P386
  2280.  
  2281. ;****************** PRT_BUF -- String buffer for printf(), etc.
  2282.  
  2283. PRT_BUF     db 20 dup(0)
  2284.  
  2285. End
  2286.  
  2287. ~~~C_PRINTF
  2288. Ideal
  2289.  
  2290. Extrn       PRT_BUF:byte,itoa:near,ltoa:near
  2291. Extrn       PUT_CHAR:near
  2292. Public      printf
  2293.  
  2294. Model Tiny
  2295. CodeSeg
  2296. P386
  2297.  
  2298. ;****************** printf() -- Print formatted string
  2299. ;void printf(char *fmt, void *args);
  2300.  
  2301. fmt         equ bp+6
  2302. args        equ bp+4
  2303.  
  2304. Proc        printf
  2305.  
  2306.             push bp                 ;Set up stack frame
  2307.             mov bp,sp
  2308.             pusha                   ;Save all registers
  2309.  
  2310.             mov si,[fmt]            ;SI = string pointer
  2311.             mov bx,[args]           ;BX = arg pointer
  2312.  
  2313. p1_loop:    lodsb                   ;Get char
  2314.             test al,al              ;Check for null
  2315.             jz p1_done
  2316.             cmp al,'%'              ;Check for '%'
  2317.             je p1_proc
  2318. p1_putc:    call PUT_CHAR           ;Output char
  2319.             jmp p1_loop             ;Loop back
  2320.  
  2321. p1_proc:    lodsb                   ;Get char
  2322.             test al,al              ;Check for null
  2323.             jz p1_done
  2324.             cmp al,'%'              ; %% = percent
  2325.             je p1_putc
  2326.             cmp al,'d'              ; %d = integer
  2327.             je p1_int
  2328.             cmp al,'l'              ; %l = long int
  2329.             je p1_long
  2330.             cmp al,'x'              ; %x = hex
  2331.             je p1_hex
  2332.             cmp al,'c'              ; %c = char
  2333.             je p1_char
  2334.             cmp al,'s'              ; %s = string
  2335.             je p1_str
  2336.             jmp p1_loop             ;Invalid, ignore
  2337.  
  2338. p1_done:    popa                    ;Restore registers
  2339.             pop bp                  ;Delete stack frame
  2340.             ret 4                   ;Return
  2341.  
  2342. p1_long:    lodsb                   ;Get char
  2343.             test al,al              ;Check for null
  2344.             jz p1_done
  2345.             cmp al,'d'              ; %ld = long integer
  2346.             je p1_lint
  2347.             cmp al,'x'              ; %lx = long hex
  2348.             je p1_lhex
  2349.             jmp p1_loop             ;Invalid, ignore
  2350.  
  2351. p1_int:     push [word bx]          ;itoa(*bx, PRT_BUF);
  2352.             push offset PRT_BUF
  2353.             call itoa
  2354.             inc bx                  ;Advance pointer
  2355.             inc bx
  2356.             mov di,offset PRT_BUF   ;Print alpha string
  2357.             jmp p1_alpha
  2358.  
  2359. p1_lint:    push [dword bx]          ;ltoa(*bx, PRT_BUF);
  2360.             push offset PRT_BUF
  2361.             call ltoa
  2362.             add bx,4                ;Advance pointer
  2363.             mov di,offset PRT_BUF   ;Print alpha string
  2364.             jmp p1_alpha
  2365.  
  2366. p1_hex:     mov ax,[bx]             ;AX = arg
  2367.             call p1_chex            ;Convert to hex
  2368.             inc bx                  ;Advance pointer
  2369.             inc bx
  2370.             jmp p1_loop             ;Loop back
  2371.  
  2372. p1_lhex:    mov ax,[bx+2]           ;AX = high word
  2373.             call p1_chex            ;Convert to hex
  2374.             mov ax,[bx]             ;AX = low word
  2375.             call p1_chex            ;Convert to hex
  2376.             add bx,4                ;Advance pointer
  2377.             jmp p1_loop             ;Loop back
  2378.  
  2379. p1_char:    mov al,[bx]             ;Output char
  2380.             int 29h
  2381.             inc bx                  ;Advance pointer
  2382.             jmp p1_loop             ;Loop back
  2383.  
  2384. p1_str:     mov al,[bx]             ;Get char
  2385.             inc bx                  ;Advance pointer
  2386.             test al,al              ;Check for null
  2387.             jz p1_sdone
  2388.             call PUT_CHAR           ;Output char
  2389.             jmp p1_str              ;Loop back
  2390.  
  2391. p1_sdone:   jmp p1_loop             ;Return to main loop
  2392.  
  2393. p1_alpha:   mov al,[di]             ;Get char
  2394.             test al,al              ;Check for null
  2395.             jz p1_sdone
  2396.             call PUT_CHAR           ;Output char
  2397.             inc di                  ;Advance pointer
  2398.             jmp p1_alpha            ;Loop back
  2399.  
  2400. p1_chex:    mov cx,4                ;4 hex digits
  2401.             xchg al,ah              ;Reverse the order
  2402.             ror ah,cl               ;of the hex digits
  2403.             ror al,cl               ;in AX
  2404.  
  2405. p1_hloop:   push ax                 ;Save AX
  2406.             and al,0Fh              ;Keep 4 bits
  2407.             cmp al,0Ah              ;Compute the hex digit,
  2408.             sbb al,69h              ;using Improved Allison's Algorithm
  2409.             das
  2410.             call PUT_CHAR           ;Output char
  2411.             pop ax                  ;Restore AX
  2412.             shr ax,4                ;Shift it over
  2413.             loop p1_hloop           ;Loop back
  2414.             ret                     ;Return
  2415.  
  2416. EndP        printf
  2417.  
  2418. End
  2419.  
  2420. ~~~C_SPRINT
  2421. Ideal
  2422.  
  2423. Extrn       PRT_BUF:byte,itoa:near,ltoa:near
  2424. Public      sprintf
  2425.  
  2426. Model Tiny
  2427. CodeSeg
  2428. P386
  2429.  
  2430. ;****************** sprintf() -- Print formatted string into string
  2431. ;void sprintf(char *strp, char *fmt, void *args);
  2432.  
  2433. strp        equ bp+8
  2434. fmt         equ bp+6
  2435. args        equ bp+4
  2436.  
  2437. Proc        sprintf
  2438.  
  2439.             push bp                 ;Set up stack frame
  2440.             mov bp,sp
  2441.             pusha                   ;Save all registers
  2442.  
  2443.             mov di,[strp]           ;DI = string pointer
  2444.             mov si,[fmt]            ;SI = format pointer
  2445.             mov bx,[args]           ;BX = arg pointer
  2446.  
  2447. p1_loop:    lodsb                   ;Get char
  2448.             test al,al              ;Check for null
  2449.             jz p1_done
  2450.             cmp al,'%'              ;Check for '%'
  2451.             je p1_proc
  2452. p1_putc:    stosb                   ;Output char
  2453.             jmp p1_loop             ;Loop back
  2454.  
  2455. p1_proc:    lodsb                   ;Get char
  2456.             test al,al              ;Check for null
  2457.             jz p1_done
  2458.             cmp al,'%'              ; %% = percent
  2459.             je p1_putc
  2460.             cmp al,'d'              ; %d = integer
  2461.             je p1_int
  2462.             cmp al,'l'              ; %l = long int
  2463.             je p1_long
  2464.             cmp al,'x'              ; %x = hex
  2465.             je p1_hex
  2466.             cmp al,'c'              ; %c = char
  2467.             je p1_char
  2468.             cmp al,'s'              ; %s = string
  2469.             je p1_str
  2470.             jmp p1_loop             ;Invalid, ignore
  2471.  
  2472. p1_done:    xor al,al               ;Store a null byte
  2473.             stosb
  2474.             popa                    ;Restore registers
  2475.             pop bp                  ;Delete stack frame
  2476.             ret 6                   ;Return
  2477.  
  2478. p1_long:    lodsb                   ;Get char
  2479.             test al,al              ;Check for null
  2480.             jz p1_done
  2481.             cmp al,'d'              ; %ld = long integer
  2482.             je p1_lint
  2483.             cmp al,'x'              ; %lx = long hex
  2484.             je p1_lhex
  2485.             jmp p1_loop             ;Invalid, ignore
  2486.  
  2487. p1_int:     push [word bx]          ;itoa(*bx, PRT_BUF);
  2488.             push offset PRT_BUF
  2489.             call itoa
  2490.             inc bx                  ;Advance pointer
  2491.             inc bx
  2492.             mov bp,offset PRT_BUF   ;Print alpha string
  2493.             jmp p1_alpha
  2494.  
  2495. p1_lint:    push [dword bx]          ;ltoa(*bx, PRT_BUF);
  2496.             push offset PRT_BUF
  2497.             call ltoa
  2498.             add bx,4                ;Advance pointer
  2499.             mov bp,offset PRT_BUF   ;Print alpha string
  2500.             jmp p1_alpha
  2501.  
  2502. p1_hex:     mov ax,[bx]             ;AX = arg
  2503.             call p1_chex            ;Convert to hex
  2504.             inc bx                  ;Advance pointer
  2505.             inc bx
  2506.             jmp p1_loop             ;Loop back
  2507.  
  2508. p1_lhex:    mov ax,[bx+2]           ;AX = high word
  2509.             call p1_chex            ;Convert to hex
  2510.             mov ax,[bx]             ;AX = low word
  2511.             call p1_chex            ;Convert to hex
  2512.             add bx,4                ;Advance pointer
  2513.             jmp p1_loop             ;Loop back
  2514.  
  2515. p1_char:    mov al,[bx]             ;Output char
  2516.             stosb
  2517.             inc bx                  ;Advance pointer
  2518.             jmp p1_loop             ;Loop back
  2519.  
  2520. p1_str:     mov al,[bx]             ;Get char
  2521.             inc bx                  ;Advance pointer
  2522.             test al,al              ;Check for null
  2523.             jz p1_sdone
  2524.             stosb                   ;Output char
  2525.             jmp p1_str              ;Loop back
  2526.  
  2527. p1_sdone:   jmp p1_loop             ;Return to main loop
  2528.  
  2529. p1_alpha:   mov al,[bp]             ;Get char
  2530.             test al,al              ;Check for null
  2531.             jz p1_sdone
  2532.             stosb                   ;Output char
  2533.             inc bp                  ;Advance pointer
  2534.             jmp p1_alpha            ;Loop back
  2535.  
  2536. p1_chex:    mov cx,4                ;4 hex digits
  2537.             xchg al,ah              ;Reverse the order
  2538.             ror ah,cl               ;of the hex digits
  2539.             ror al,cl               ;in AX
  2540.  
  2541. p1_hloop:   push ax                 ;Save AX
  2542.             and al,0Fh              ;Keep 4 bits
  2543.             cmp al,0Ah              ;Compute the hex digit,
  2544.             sbb al,69h              ;using Improved Allison's Algorithm
  2545.             das
  2546.             stosb                   ;Output char
  2547.             pop ax                  ;Restore AX
  2548.             shr ax,4                ;Shift it over
  2549.             loop p1_hloop           ;Loop back
  2550.             ret                     ;Return
  2551.  
  2552. EndP        sprintf
  2553.  
  2554. End
  2555.  
  2556. ~~~C_FPRINT
  2557. Ideal
  2558.  
  2559. Extrn       PRT_BUF:byte,fputc:near,itoa:near,ltoa:near
  2560. Public      fprintf
  2561.  
  2562. Model Tiny
  2563. CodeSeg
  2564. P386
  2565.  
  2566. ;****************** fprintf() -- Print formatted string to file
  2567. ;void fprintf(int fp, char *fmt, void *args);
  2568.  
  2569. fp          equ bp+8
  2570. fmt         equ bp+6
  2571. args        equ bp+4
  2572.  
  2573. Proc        fprintf
  2574.  
  2575.             push bp                 ;Set up stack frame
  2576.             mov bp,sp
  2577.             pusha                   ;Save all registers
  2578.  
  2579.             mov dx,[fp]             ;DX = file pointer
  2580.             mov si,[fmt]            ;SI = string pointer
  2581.             mov bx,[args]           ;BX = arg pointer
  2582.  
  2583. p1_loop:    lodsb                   ;Get char
  2584.             test al,al              ;Check for null
  2585.             jz p1_done
  2586.             cmp al,'%'              ;Check for '%'
  2587.             je p1_proc
  2588. p1_putc:    push dx ax              ;Output char
  2589.             call fputc
  2590.             jmp p1_loop             ;Loop back
  2591.  
  2592. p1_proc:    lodsb                   ;Get char
  2593.             test al,al              ;Check for null
  2594.             jz p1_done
  2595.             cmp al,'%'              ; %% = percent
  2596.             je p1_putc
  2597.             cmp al,'d'              ; %d = integer
  2598.             je p1_int
  2599.             cmp al,'l'              ; %l = long int
  2600.             je p1_long
  2601.             cmp al,'x'              ; %x = hex
  2602.             je p1_hex
  2603.             cmp al,'c'              ; %c = char
  2604.             je p1_char
  2605.             cmp al,'s'              ; %s = string
  2606.             je p1_str
  2607.             jmp p1_loop             ;Invalid, ignore
  2608.  
  2609. p1_done:    popa                    ;Restore registers
  2610.             pop bp                  ;Delete stack frame
  2611.             ret 6                   ;Return
  2612.  
  2613. p1_long:    lodsb                   ;Get char
  2614.             test al,al              ;Check for null
  2615.             jz p1_done
  2616.             cmp al,'d'              ; %ld = long integer
  2617.             je p1_lint
  2618.             cmp al,'x'              ; %lx = long hex
  2619.             je p1_lhex
  2620.             jmp p1_loop             ;Invalid, ignore
  2621.  
  2622. p1_int:     push [word bx]          ;itoa(*bx, PRT_BUF);
  2623.             push offset PRT_BUF
  2624.             call itoa
  2625.             inc bx                  ;Advance pointer
  2626.             inc bx
  2627.             mov di,offset PRT_BUF   ;Print alpha string
  2628.             jmp p1_alpha
  2629.  
  2630. p1_lint:    push [dword bx]          ;ltoa(*bx, PRT_BUF);
  2631.             push offset PRT_BUF
  2632.             call ltoa
  2633.             add bx,4                ;Advance pointer
  2634.             mov di,offset PRT_BUF   ;Print alpha string
  2635.             jmp p1_alpha
  2636.  
  2637. p1_hex:     mov ax,[bx]             ;AX = arg
  2638.             call p1_chex            ;Convert to hex
  2639.             inc bx                  ;Advance pointer
  2640.             inc bx
  2641.             jmp p1_loop             ;Loop back
  2642.  
  2643. p1_lhex:    mov ax,[bx+2]           ;AX = high word
  2644.             call p1_chex            ;Convert to hex
  2645.             mov ax,[bx]             ;AX = low word
  2646.             call p1_chex            ;Convert to hex
  2647.             add bx,4                ;Advance pointer
  2648.             jmp p1_loop             ;Loop back
  2649.  
  2650. p1_char:    mov al,[bx]             ;Output char
  2651.             push dx ax
  2652.             call fputc
  2653.             inc bx                  ;Advance pointer
  2654.             jmp p1_loop             ;Loop back
  2655.  
  2656. p1_str:     mov al,[bx]             ;Get char
  2657.             inc bx                  ;Advance pointer
  2658.             test al,al              ;Check for null
  2659.             jz p1_sdone
  2660.             push dx ax              ;Output char
  2661.             call fputc
  2662.             jmp p1_str              ;Loop back
  2663.  
  2664. p1_sdone:   jmp p1_loop             ;Return to main loop
  2665.  
  2666. p1_alpha:   mov al,[di]             ;Get char
  2667.             test al,al              ;Check for null
  2668.             jz p1_sdone
  2669.             push dx ax              ;Output char
  2670.             call fputc
  2671.             inc di                  ;Advance pointer
  2672.             jmp p1_alpha            ;Loop back
  2673.  
  2674. p1_chex:    mov cx,4                ;4 hex digits
  2675.             xchg al,ah              ;Reverse the order
  2676.             ror ah,cl               ;of the hex digits
  2677.             ror al,cl               ;in AX
  2678.  
  2679. p1_hloop:   push ax                 ;Save AX
  2680.             and al,0Fh              ;Keep 4 bits
  2681.             cmp al,0Ah              ;Compute the hex digit,
  2682.             sbb al,69h              ;using Improved Allison's Algorithm
  2683.             das
  2684.             push dx ax              ;Output char
  2685.             call fputc
  2686.             pop ax                  ;Restore AX
  2687.             shr ax,4                ;Shift it over
  2688.             loop p1_hloop           ;Loop back
  2689.             ret                     ;Return
  2690.  
  2691. EndP        fprintf
  2692.  
  2693. End
  2694.  
  2695. ~~~C_XPRINT
  2696. Ideal
  2697.  
  2698. Extrn       PRT_BUF:byte,itoa:near,ltoa:near
  2699. Public      xprintf
  2700.  
  2701. Model Tiny
  2702. CodeSeg
  2703. P386
  2704.  
  2705. ;****************** xprintf() -- Print formatted string, generalized
  2706. ;void xprintf(void *func, char *fmt, void *args);
  2707.  
  2708. func        equ bp+8
  2709. fmt         equ bp+6
  2710. args        equ bp+4
  2711.  
  2712. Proc        xprintf
  2713.  
  2714.             push bp                 ;Set up stack frame
  2715.             mov bp,sp
  2716.             pusha                   ;Save all registers
  2717.  
  2718.             mov dx,[func]           ;DX = function pointer
  2719.             mov si,[fmt]            ;SI = string pointer
  2720.             mov bx,[args]           ;BX = arg pointer
  2721.  
  2722. p1_loop:    lodsb                   ;Get char
  2723.             test al,al              ;Check for null
  2724.             jz p1_done
  2725.             cmp al,'%'              ;Check for '%'
  2726.             je p1_proc
  2727. p1_putc:    push ax                 ;Output char
  2728.             call dx
  2729.             jmp p1_loop             ;Loop back
  2730.  
  2731. p1_proc:    lodsb                   ;Get char
  2732.             test al,al              ;Check for null
  2733.             jz p1_done
  2734.             cmp al,'%'              ; %% = percent
  2735.             je p1_putc
  2736.             cmp al,'d'              ; %d = integer
  2737.             je p1_int
  2738.             cmp al,'l'              ; %l = long int
  2739.             je p1_long
  2740.             cmp al,'x'              ; %x = hex
  2741.             je p1_hex
  2742.             cmp al,'c'              ; %c = char
  2743.             je p1_char
  2744.             cmp al,'s'              ; %s = string
  2745.             je p1_str
  2746.             jmp p1_loop             ;Invalid, ignore
  2747.  
  2748. p1_done:    popa                    ;Restore registers
  2749.             pop bp                  ;Delete stack frame
  2750.             ret 6                   ;Return
  2751.  
  2752. p1_long:    lodsb                   ;Get char
  2753.             test al,al              ;Check for null
  2754.             jz p1_done
  2755.             cmp al,'d'              ; %ld = long integer
  2756.             je p1_lint
  2757.             cmp al,'x'              ; %lx = long hex
  2758.             je p1_lhex
  2759.             jmp p1_loop             ;Invalid, ignore
  2760.  
  2761. p1_int:     push [word bx]          ;itoa(*bx, PRT_BUF);
  2762.             push offset PRT_BUF
  2763.             call itoa
  2764.             inc bx                  ;Advance pointer
  2765.             inc bx
  2766.             mov di,offset PRT_BUF   ;Print alpha string
  2767.             jmp p1_alpha
  2768.  
  2769. p1_lint:    push [dword bx]         ;ltoa(*bx, PRT_BUF);
  2770.             push offset PRT_BUF
  2771.             call ltoa
  2772.             add bx,4                ;Advance pointer
  2773.             mov di,offset PRT_BUF   ;Print alpha string
  2774.             jmp p1_alpha
  2775.  
  2776. p1_hex:     mov ax,[bx]             ;AX = arg
  2777.             call p1_chex            ;Convert to hex
  2778.             inc bx                  ;Advance pointer
  2779.             inc bx
  2780.             jmp p1_loop             ;Loop back
  2781.  
  2782. p1_lhex:    mov ax,[bx+2]           ;AX = high word
  2783.             call p1_chex            ;Convert to hex
  2784.             mov ax,[bx]             ;AX = low word
  2785.             call p1_chex            ;Convert to hex
  2786.             add bx,4                ;Advance pointer
  2787.             jmp p1_loop             ;Loop back
  2788.  
  2789. p1_char:    mov al,[bx]             ;Output char
  2790.             push ax
  2791.             call dx
  2792.             inc bx                  ;Advance pointer
  2793.             jmp p1_loop             ;Loop back
  2794.  
  2795. p1_str:     mov al,[bx]             ;Get char
  2796.             inc bx                  ;Advance pointer
  2797.             test al,al              ;Check for null
  2798.             jz p1_sdone
  2799.             push ax                 ;Output char
  2800.             call dx
  2801.             jmp p1_str              ;Loop back
  2802.  
  2803. p1_sdone:   jmp p1_loop             ;Return to main loop
  2804.  
  2805. p1_alpha:   mov al,[di]             ;Get char
  2806.             test al,al              ;Check for null
  2807.             jz p1_sdone
  2808.             push ax                 ;Output char
  2809.             call dx
  2810.             inc di                  ;Advance pointer
  2811.             jmp p1_alpha            ;Loop back
  2812.  
  2813. p1_chex:    mov cx,4                ;4 hex digits
  2814.             xchg al,ah              ;Reverse the order
  2815.             ror ah,cl               ;of the hex digits
  2816.             ror al,cl               ;in AX
  2817.  
  2818. p1_hloop:   push ax                 ;Save AX
  2819.             and al,0Fh              ;Keep 4 bits
  2820.             cmp al,0Ah              ;Compute the hex digit,
  2821.             sbb al,69h              ;using Improved Allison's Algorithm
  2822.             das
  2823.             push ax                 ;Output char
  2824.             call dx
  2825.             pop ax                  ;Restore AX
  2826.             shr ax,4                ;Shift it over
  2827.             loop p1_hloop           ;Loop back
  2828.             ret                     ;Return
  2829.  
  2830. EndP        xprintf
  2831.  
  2832. End
  2833.  
  2834. ~~~C_CPULVL
  2835. Ideal
  2836.  
  2837. Public      cputype
  2838.  
  2839. Model Tiny
  2840. P186
  2841. CodeSeg
  2842.  
  2843. ;**************************** cputype() -- Returns CPU level
  2844. ;int cputype(void);
  2845.  
  2846. Proc        cputype
  2847.  
  2848.             pusha              ;Save all registers
  2849.  
  2850.             call p1_getcpu     ;Call main procedure
  2851.  
  2852.             shr ax,8           ;AL = AH, AH = 0
  2853.             mov bp,sp          ;Change pushed AX
  2854.             mov [bp+14],ax
  2855.             popa               ;Restore registers
  2856.             ret                ;Return
  2857.  
  2858. p1_getcpu:  mov cx,0121h       ;If CH can be shifted by 21h,
  2859.             shl ch,cl          ;then it's an 8086, because
  2860.             jz p1_8086         ;a 186+ limits shift counts.
  2861.  
  2862.             push sp            ;If SP is pushed as its
  2863.             pop ax             ;original value, then
  2864.             cmp ax,sp          ;it's a 286+.
  2865.             jne p1_186
  2866.  
  2867.             pushf              ;Save flags
  2868.             cli                ;No interrupts
  2869.             pushf              ;AX = flags
  2870.             pop ax
  2871.             xor ax,7000h       ;Toggle IOPL bit
  2872.             push ax            ;Flags = AX
  2873.             popf
  2874.             pushf              ;BX = flags
  2875.             pop bx
  2876.             popf               ;Restore flags
  2877.             cmp ax,bx          ;If the bit was not
  2878.             jne p1_286         ;reset, it's a 386+
  2879. P386
  2880.             push bp            ;Align stack to dword
  2881.             mov bp,sp
  2882.             and sp,0FFFCh
  2883.             pushfd             ;Save eflags
  2884.             cli                ;No interrupts
  2885.             pushfd             ;EAX = eflags
  2886.             pop eax
  2887.             mov ebx,eax        ;EBX = eflags
  2888.             xor eax,40000h     ;Toggle AC bit
  2889.             push eax           ;Eflags = EAX
  2890.             popfd
  2891.             pushfd             ;EAX = eflags
  2892.             pop eax
  2893.             popfd              ;Restore eflags
  2894.             mov sp,bp          ;Restore stack
  2895.             pop bp
  2896.             cmp eax,ebx        ;If the bit was not
  2897.             je p1_386          ;reset, it's a 486+
  2898.  
  2899.             pushfd             ;Save eflags
  2900.             cli                ;No interrupts
  2901.             pushfd             ;EAX = eflags
  2902.             pop eax
  2903.             xor eax,200000h    ;Toggle ID bit
  2904.             push eax           ;Eflags = EAX
  2905.             popfd
  2906.             pushfd             ;EBX = eflags
  2907.             pop ebx
  2908.             popfd              ;Restore eflags
  2909.             cmp eax,ebx        ;If the bit was not
  2910.             jne p1_486         ;reset, it's a 586+
  2911. P586
  2912.             xor eax,eax        ;EAX = 1
  2913.             inc ax
  2914.             cpuid              ;Get CPU type
  2915.             ret                ;Return
  2916. P186
  2917. p1_486:     mov ah,4           ;486, return 4
  2918.             ret
  2919.  
  2920. p1_386:     mov ah,3           ;386, return 3
  2921.             ret
  2922.  
  2923. p1_286:     mov ah,2           ;286, return 2
  2924.             ret
  2925.  
  2926. p1_186:     mov ah,1           ;186, return 1
  2927.             ret
  2928.  
  2929. p1_8086:    mov ah,0           ;8086, return 0
  2930.             ret
  2931.  
  2932. EndP        cputype
  2933.  
  2934. End
  2935.  
  2936. ~~~C_FPULVL
  2937. Ideal
  2938.  
  2939. Public      fputype
  2940.  
  2941. Model Tiny
  2942. P186
  2943. CodeSeg
  2944.  
  2945. ;**************************** fputype() -- Returns FPU level, init FPU
  2946. ;int fputype(void);                        -1 means no FPU
  2947.  
  2948. Proc        fputype
  2949.  
  2950.             pusha              ;Save all registers
  2951.  
  2952.             call p2_getfpu     ;Get FPU type
  2953.  
  2954.             mov bp,sp          ;Change pushed AX
  2955.             mov [bp+14],ax
  2956.             popa               ;Restore registers
  2957.             ret                ;Return
  2958. P8087
  2959. p2_getfpu:  fninit             ;Initialize FPU
  2960.             mov [Junk],55AAh   ;Set junk value
  2961.             fnstsw [Junk]      ;Store status word
  2962.             cmp [byte Junk],0  ;If it's not 0, no FPU
  2963.             jne p2_nofpu
  2964.             fnstcw [Junk]      ;Store control word
  2965.             mov ax,[Junk]      ;If the bits are not the way
  2966.             and ax,103Fh       ;they should be, no FPU
  2967.             cmp ax,3Fh
  2968.             jne p2_nofpu
  2969.  
  2970.             and [Junk],0FF7Fh  ;Clear interrupt bit
  2971.             fldcw [Junk]       ;Load control word
  2972.             fdisi              ;Disable interrupts
  2973.             fstcw [Junk]       ;Store control word
  2974.             test [Junk],80h    ;If it changed, it's an 8087
  2975.             jnz p2_8087
  2976. P286
  2977. P287
  2978.             finit              ;Re-initialize
  2979.             fld1               ;Divide 1 by 0 to get
  2980.             fldz               ;a positive infinity
  2981.             fdiv
  2982.             fld st             ;Get a negative infinity
  2983.             fchs
  2984.             fcompp             ;Compare them
  2985.             fstsw ax           ;Store status word
  2986.             sahf               ;If the FPU thought that they
  2987.             je p2_287          ;were equal, it's a 287
  2988.  
  2989.             mov ax,3           ;387, return 3
  2990.             finit              ;Init processor
  2991.             ret
  2992.  
  2993. p2_287:     mov ax,2           ;287, return 2
  2994.             finit              ;Init processor
  2995.             ret
  2996. P186
  2997. P8087
  2998. p2_8087:    xor ax,ax          ;8087, return 0
  2999.             finit              ;Init processor
  3000.             ret
  3001.  
  3002. p2_nofpu:   mov ax,-1          ;No FPU, return -1
  3003.             ret
  3004.  
  3005. Junk        dw 0
  3006.  
  3007. EndP        fputype
  3008.  
  3009. End
  3010.  
  3011. ~~~C_RAND
  3012. Ideal
  3013.  
  3014. Public      rand,srand,truerand
  3015.  
  3016. Model Tiny
  3017. P386
  3018. CodeSeg
  3019.  
  3020. RandNum     dd 0                    ;Random number
  3021.  
  3022. ;****************** rand() -- Returns a random number below N
  3023. ;int rand(int max);
  3024.  
  3025. max         equ bp+4
  3026.  
  3027. Proc        rand
  3028.  
  3029.             push bp                 ;Set up stack frame
  3030.             mov bp,sp
  3031.             push bx edx             ;Save registers
  3032.  
  3033.             imul edx,[RandNum],19660Dh
  3034.             add edx,10DCDh          ;EAX = RandNum * 19660Dh + 10DCDh
  3035.             mov [RandNum],edx       ;Save random number
  3036.             shr edx,15              ;AX = bits 15-30
  3037.             xchg ax,dx
  3038.             mov bx,[max]            ;BX = maximum
  3039.             xor dx,dx               ;Zero DX
  3040.             test bx,bx              ;Can't divide by zero
  3041.             jz p1_skip
  3042.             div bx                  ;Divide by BX
  3043. p1_skip:    xchg ax,dx              ;Result in AX
  3044.  
  3045.             pop edx bx              ;Restore registers
  3046.             pop bp                  ;Delete stack frame
  3047.             ret 2                   ;Return
  3048.  
  3049. EndP        rand
  3050.  
  3051. ;****************** srand() -- Seeds the RNG with the time
  3052. ;void srand(void);
  3053.  
  3054. Proc        srand
  3055.  
  3056.             push bp                 ;Set up stack frame
  3057.             mov bp,sp
  3058.             push es eax             ;Save registers
  3059.  
  3060.             push 40h                ;ES = BIOS segment
  3061.             pop es
  3062.  
  3063.             mov eax,[es:6Ch]        ;Get low word
  3064.             mov [RandNum],eax       ;Save it
  3065.  
  3066.             pop eax es              ;Restore registers
  3067.             pop bp                  ;Delete stack frame
  3068.             ret                     ;Return
  3069.  
  3070. EndP        srand
  3071.  
  3072. ;****************** truerand() -- Returns a true random number below N
  3073. ;int truerand(int max);           Extremely slow, but it works
  3074.  
  3075. max         equ bp+4
  3076.  
  3077. Proc        truerand
  3078.  
  3079.             push bp                 ;Set up stack frame
  3080.             mov bp,sp
  3081.             push bx cx dx           ;Save registers
  3082.  
  3083.             mov cx,96               ;96 iterations
  3084.             cli                     ;No interrupts allowed
  3085.  
  3086. p1_loop:    mov al,06h              ;Set timer command
  3087.             out 43h,al
  3088.             jmp $+2
  3089.             in al,40h               ;Read LSB of timer
  3090.             xor dl,al               ;XOR into DX
  3091.             jmp $+2
  3092.             in al,40h               ;Read MSB of timer
  3093.             xor dl,al               ;XOR into DX
  3094.             rol dx,3                ;Rotate left
  3095.             loop p1_loop            ;Loop back
  3096.  
  3097.             sti                     ;Enable interrupts
  3098.             xchg ax,dx              ;Result in AX
  3099.  
  3100.             mov bx,[max]            ;BX = maximum
  3101.             xor dx,dx               ;Zero DX
  3102.             test bx,bx              ;Can't divide by zero
  3103.             jz p3_skip
  3104.             div bx                  ;Divide by BX
  3105. p3_skip:    xchg ax,dx              ;Result in AX
  3106.  
  3107.             pop dx cx bx            ;Restore registers
  3108.             pop bp                  ;Delete stack frame
  3109.             ret 2                   ;Return
  3110.  
  3111. EndP        truerand
  3112.  
  3113. End
  3114.  
  3115. ~~~C_DELAY
  3116. Ideal
  3117.  
  3118. Public      delay
  3119.  
  3120. Model Tiny
  3121. P386
  3122. CodeSeg
  3123.  
  3124. ;****************** delay() -- Delay in milliseconds
  3125. ;void delay(int dtime);
  3126.  
  3127. dtime       equ bp+4
  3128.  
  3129. Proc        delay
  3130.  
  3131.             push bp                 ;Set up stack frame
  3132.             mov bp,sp
  3133.             pusha                   ;Save registers
  3134.  
  3135.             mov ax,[dtime]          ;AX = time in milliseconds
  3136.             mov dx,1000             ;Multiply by 1000
  3137.             mul dx                  ;DX:AX = time in microseconds
  3138.  
  3139.             mov cx,dx               ;CX:DX = time
  3140.             xchg dx,ax
  3141.             mov ah,86h              ;BIOS Delay Service
  3142.             int 15h
  3143.  
  3144.             popa                    ;Restore registers
  3145.             pop bp                  ;Delete stack frame
  3146.             ret 2                   ;Return
  3147.  
  3148. EndP        delay
  3149.  
  3150. End
  3151.  
  3152. ~~~C_SOUND
  3153. Ideal
  3154.  
  3155. Public      sound,nosound
  3156.  
  3157. Model Tiny
  3158. P386
  3159. CodeSeg
  3160.  
  3161. ;****************** sound() -- Turn on speaker at specific frequency
  3162. ;void sound(int freq);
  3163.  
  3164. freq        equ bp+4
  3165.  
  3166. Proc        sound
  3167.  
  3168.             push bp                 ;Set up stack frame
  3169.             mov bp,sp
  3170.             pusha                   ;Save registers
  3171.  
  3172.             mov dx,12h              ;BX = 1193180 / freq.
  3173.             mov ax,34DCh
  3174.             mov bx,[freq]
  3175.             div bx
  3176.             xchg bx,ax
  3177.  
  3178.             mov al,0B6h             ;Set frequency
  3179.             out 43h,al
  3180.             mov al,bl
  3181.             out 42h,al
  3182.             mov al,bh
  3183.             out 42h,al
  3184.  
  3185.             in al,61h               ;Turn on speaker
  3186.             or al,3
  3187.             out 61h,al
  3188.  
  3189.             popa                    ;Restore registers
  3190.             pop bp                  ;Delete stack frame
  3191.             ret 2                   ;Return
  3192.  
  3193. EndP        sound
  3194.  
  3195. ;****************** nosound() -- Turn off speaker
  3196. ;void nosound(void);
  3197.  
  3198. Proc        nosound
  3199.  
  3200.             push ax                 ;Save AX
  3201.  
  3202.             in al,61h               ;Turn off speaker
  3203.             and al,0FCh
  3204.             out 61h,al
  3205.  
  3206.             pop ax                  ;Restore AX
  3207.             ret                     ;Return
  3208.  
  3209. EndP        nosound
  3210.  
  3211. End
  3212.